microsoft / pxt-arcade

Arcade game editor based on Microsoft MakeCode

Home Page:https://arcade.makecode.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Arcade game ELF executables freeze on exit - Raspberry Pi

Vegz78 opened this issue · comments

Describe the bug
SHORT:
When running MakeCode Arcade ELF executables on Raspberry Pi OS, the main process turns defunct/zombie and the game hangs on exit.

LONG:

  1. When running the game from the local console, tty1, in a bash shell, the game itself runs fine, with keyboard controls, reseting/restarting and everything, even though the game process turns zombie/defunct(first/main light weight process of 8 LWP, the other 7 seem normal).

  2. When exiting the same already running game in however way(in-game options or kill -9(kill -INT or -TERM does not work) command from ssh, or any keyboard shortcut) the game process dies and is reaped, but control/session is not handed back to the calling parent bash process at tty1, which:
    -still has framebuffer filled with the last frozen image of the game,
    -has no visible command prompt or response to remote commands to the console,
    -local keyboard is unresponsive

  3. The only way I’ve found to regain control of the tty1 console is to issue a reboot or kill the running bash/parent process(requiring new login), or rebooting using CTRL+ALT+DEL, which for some reason works for rebooting on my systems…

To Reproduce
Steps to reproduce the behavior:

  1. Go to 'http://arcade.makecode.com/' and compile and download a game as ELF with '?hw=rpi&compile=rawELF' in the browser URL
  2. From the console/shell on a Raspberry Pi, make the game executable and run it with the command './anygame.elf'
  3. Try to quit the game with 'CTRL-C' or from the in-game menu or shortcut keys
  4. The console/shell and whole system hangs/freezes with a frozen image of the game and unresponsive inputs. Can only regain control of system by ssh and killing the calling console/shell process or rebooting the system.

Expected behavior
The game process runs without turning zombie/defunct and exits gracefully by clearing the framebuffer and handing control back to the calling console/shell process.

Screenshots
Not relevant.

Desktop (please complete the following information):

  • OS/Browser: Any OS/Browser for compiling and downloading, running on Rasperry Pi OS(tested stretch and buster) on Raspberry Pi 3 or 4.
  • Version: Many different versions of MakeCode Arcade and Raspberry Pi/RPi OS'es.

Additional context
With reference to the latest posts in the forum thread https://forum.makecode.com/t/how-to-launch-makecode-arcade-uf2s-in-raspbian-retropie and of lately absent responses from @mmoskal and @pelikhan. As soon as this bug is fixed, MakeCode Arcade would run great natively on Raspberry Pis and open up a large platform for hobbyist arcade coders and gamers. I would be more than happy to help out testing changes/bugfixes, and to help writing a tutorial for compiling and running MakeCode Arcade games natively when this bug is fixed. Don't hesitate to contact me(here on GitHub, on the MakeCode forum or by mail, which @mmoskal has)!

Br,
Vegard

Hi @mmoskal,

With your great help earlier, and some more help from @willmtemple, I finally figured out this issue:

  1. There is no stable parent process with the same PID when running the elfs natively, so that other programs see the game as having quit, when in fact the game instead starts with new PIDs on game over and game reset events. The consequence of this, e.g. for RetroPie etc., is that EmulationStation reactivates and the game keeps running in the background.
  2. Regarding freezing/hanging on exit, the issue is that the framebuffer and keyboard modes are not cleaned up and released back to the calling/parent process/shell on exit.

I believe, with the help from Will, that this might be related to this file, here.
https://github.com/microsoft/pxt-common-packages/blob/9c7b6e3f7b11a1f1d9f53ae6dec235a0619c31a0/libs/core---linux/target.cpp#L15

Not sure if it would be possible to change the rpi target execution sequence to add a stable parent process until exit and cleaning up the framebuffer and keyboard modes without affecting how it runs on uf2 boot images on the RPi Zero etc.?

Anyways, this is what I have tried to do in my finally working work-around, which I hope might be of help to others for enjoying MakeCode Arcade games in RetroPie until and whether this issue is adressed by the professionals at MakeCode:
https://github.com/Vegz78/McAirpos

Br,
Vegard

Closing this one, as it now is known what causes the freeze(framebuffer and keyboard modes are not released), assumed to be known in what pxt-arcade file this could be remedied(link above) and there is a working work-around for RPi which now is pretty stably implemented and working ok for most RPis with https://github.com/Vegz78/McAirpos.

Sorry I never had time to look into this... :/

With reference to this unrelated pxt-arcade issue, where I coincidentally stumbled over the ioctl logic in the WDisplay constructor in the file screen.cpp that sets the screen to graphics mode, but does not return it to the previous text mode on game exit, as described in this issue here above:
https://github.com/microsoft/pxt-common-packages/blob/master/libs/screen---linux/screen.cpp#L197

I then played a little around with a local pxt arcade server, and tried to utilize the same methodology as in termfix and used in McAirpos. The idea for the solution is basically to ioctl get the initial screen and keyboard mode on game start and store into two variables, and then, on game exit, to restore the ioctl screen and keyboard modes to the values they had before and if the screen mode was switched to KD_GRAPHICS(and keyboard to RAW).

Thinking that it could be a good idea to try to solve this issue here at the source, i tried to implement this in a custom destructor for the WDisplay class. But, since WDisplay turns out to be initialized as what I understand is a static singleton, it seems like the destructor is never called upon game exit(?)...:
https://github.com/microsoft/pxt-common-packages/blob/master/libs/screen---linux/screen.cpp#L43
https://github.com/microsoft/pxt-common-packages/blob/master/libs/core---linux/target.cpp#L12

The singleton(and main() function) method that creates the object seems further to be defined as a macro inside the pxtbase.h header file:
https://github.com/microsoft/pxt-common-packages/blob/master/libs/base/pxtbase.h#L1217
(https://github.com/microsoft/pxt-common-packages/blob/master/libs/base/pxtbase.h#L1202)

I therefore have trouble finding out how to reference the WDisplay object(not in pxt namespace etc.), but more importantly, where and how it would be best to call ioctl restoration code just before game exit.

I believe this would make the linux executables, both .elfs on general ARM linux and .uf2s for the custom MakeCode RPi image run more robustly, by returning to the screen and keyboard modes that was before game launch(and thereby not experiencing a frame freeze on last game screen which requires a reboot(or as special program) to reset).

If anyone has a good idea for the where and how, please reply, and we could maybe work out a pull request together.