diff --git a/src/devices.cpp b/src/devices.cpp index 481f37b38..cc159c9e9 100644 --- a/src/devices.cpp +++ b/src/devices.cpp @@ -238,6 +238,9 @@ void devices_reset_ext(int hardreset) void devices_reset(int hardreset) { memset(device_reset_done, 0, sizeof(device_reset_done)); +#ifdef AMIBERRY + uaelib_host_cleanup(); +#endif // must be first init_eventtab(); init_shm(); @@ -385,6 +388,9 @@ void devices_update_sync(float svpos, float syncadjust) void virtualdevice_free(void) { +#ifdef AMIBERRY + uaelib_host_cleanup(); +#endif #ifdef WITH_PPC // must be first uae_ppc_free(); diff --git a/src/include/uae.h b/src/include/uae.h index e77d1c5fa..da49f0210 100644 --- a/src/include/uae.h +++ b/src/include/uae.h @@ -115,6 +115,7 @@ void filesys_addexternals (void); #ifdef AMIBERRY extern std::vector get_cd_drives(); extern int add_filesys_unit(struct uaedev_config_info* ci, bool custom); +extern void uaelib_host_cleanup(); #endif #endif /* UAE_UAE_H */ diff --git a/src/osdep/gfx_prefs_check.cpp b/src/osdep/gfx_prefs_check.cpp index 0784eb7a1..19172eaf9 100644 --- a/src/osdep/gfx_prefs_check.cpp +++ b/src/osdep/gfx_prefs_check.cpp @@ -60,6 +60,13 @@ int check_prefs_changed_gfx() int c = 0; bool monitors[MAX_AMIGAMONITORS]{}; + const bool native_code_changed = currprefs.native_code != changed_prefs.native_code; + if (native_code_changed) { + if (currprefs.native_code && !changed_prefs.native_code) + uaelib_host_cleanup(); + currprefs.native_code = changed_prefs.native_code; + } + if (!config_changed && !display_change_requested) return 0; @@ -535,7 +542,7 @@ int check_prefs_changed_gfx() currprefs.minimized_pause != changed_prefs.minimized_pause || currprefs.minimized_input != changed_prefs.minimized_input || currprefs.capture_always != changed_prefs.capture_always || - currprefs.native_code != changed_prefs.native_code || + native_code_changed || currprefs.alt_tab_release != changed_prefs.alt_tab_release || currprefs.ctrl_alt_release != changed_prefs.ctrl_alt_release || currprefs.use_retroarch_quit != changed_prefs.use_retroarch_quit || @@ -569,7 +576,6 @@ int check_prefs_changed_gfx() currprefs.minimized_pause = changed_prefs.minimized_pause; currprefs.minimized_input = changed_prefs.minimized_input; currprefs.capture_always = changed_prefs.capture_always; - currprefs.native_code = changed_prefs.native_code; currprefs.alt_tab_release = changed_prefs.alt_tab_release; currprefs.ctrl_alt_release = changed_prefs.ctrl_alt_release; currprefs.use_retroarch_quit = changed_prefs.use_retroarch_quit; diff --git a/src/uaelib.cpp b/src/uaelib.cpp index 98b9efef8..7fb5d1747 100644 --- a/src/uaelib.cpp +++ b/src/uaelib.cpp @@ -432,6 +432,35 @@ static const uae_u32 HOST_SHELL_STATUS_INVALID = 0; static const uae_u32 HOST_SHELL_STATUS_RUNNING = 1; static const uae_u32 HOST_SHELL_STATUS_EXITED = 0x80000000; static const uae_u32 HOST_SHELL_IO_MAX = 4096; +#if !defined(_WIN32) +static const int HOST_SHELL_WAIT_INTERVAL_MS = 10; +static const int HOST_SHELL_TERM_TIMEOUT_MS = 1000; +static const int HOST_SHELL_KILL_TIMEOUT_MS = 1000; +#endif + +static constexpr bool uaelib_host_trap_requires_native_code(uae_u32 trap) +{ + return trap >= 88 && trap <= 95 && trap != 93; +} + +static constexpr uae_u32 uaelib_host_trap_denied_result(uae_u32 trap) +{ + return trap == 91 || trap == 92 ? static_cast(-1) : 0; +} + +static_assert(uaelib_host_trap_requires_native_code(88)); +static_assert(uaelib_host_trap_requires_native_code(89)); +static_assert(uaelib_host_trap_requires_native_code(90)); +static_assert(uaelib_host_trap_requires_native_code(91)); +static_assert(uaelib_host_trap_requires_native_code(92)); +static_assert(!uaelib_host_trap_requires_native_code(93)); +static_assert(uaelib_host_trap_requires_native_code(94)); +static_assert(uaelib_host_trap_requires_native_code(95)); +static_assert(!uaelib_host_trap_requires_native_code(96)); +static_assert(uaelib_host_trap_denied_result(90) == 0); +static_assert(uaelib_host_trap_denied_result(91) == static_cast(-1)); +static_assert(uaelib_host_trap_denied_result(92) == static_cast(-1)); +static_assert(uaelib_host_trap_denied_result(94) == HOST_SHELL_STATUS_INVALID); #if !defined(_WIN32) static int host_shell_exit_code(int status) @@ -497,6 +526,34 @@ static uae_u32 host_shell_update_status(ShellSession& session) #endif } +#if !defined(_WIN32) +static bool host_shell_wait_for_exit(ShellSession& session, int timeout_ms) +{ + for (int elapsed = 0; elapsed < timeout_ms; elapsed += HOST_SHELL_WAIT_INTERVAL_MS) { + if ((host_shell_update_status(session) & HOST_SHELL_STATUS_EXITED) != 0) + return true; + sleep_millis(HOST_SHELL_WAIT_INTERVAL_MS); + } + return (host_shell_update_status(session) & HOST_SHELL_STATUS_EXITED) != 0; +} + +static void host_shell_terminate(ShellSession& session) +{ + if ((host_shell_update_status(session) & HOST_SHELL_STATUS_EXITED) != 0) + return; + + if (kill(session.pid, SIGTERM) < 0 && errno != ESRCH) + write_log("Failed to terminate host shell process %d: %s\n", session.pid, strerror(errno)); + if (host_shell_wait_for_exit(session, HOST_SHELL_TERM_TIMEOUT_MS)) + return; + + if (kill(session.pid, SIGKILL) < 0 && errno != ESRCH) + write_log("Failed to kill host shell process %d: %s\n", session.pid, strerror(errno)); + if (!host_shell_wait_for_exit(session, HOST_SHELL_KILL_TIMEOUT_MS)) + write_log("Timed out waiting for host shell process %d to exit\n", session.pid); +} +#endif + static uae_u32 uaelib_host_open(TrapContext* ctx, uaecptr command) { char cmd[HOST_SHELL_CMD_MAX]; @@ -856,16 +913,19 @@ static uae_u32 uaelib_host_close(TrapContext* ctx, uae_u32 handle) close(session.outfd); session.outfd = -1; } - if ((host_shell_update_status(session) & HOST_SHELL_STATUS_EXITED) == 0) { - kill(session.pid, SIGTERM); - waitpid(session.pid, NULL, 0); - } + host_shell_terminate(session); shell_sessions.erase(handle); return 1; #endif } +void uaelib_host_cleanup() +{ + while (!shell_sessions.empty()) + uaelib_host_close(nullptr, shell_sessions.begin()->first); +} + // Host platform ids reported by trap 96; 0 (unknown trap on older // builds) means the guest should assume a POSIX host. static uae_u32 uaelib_host_get_platform(void) @@ -882,15 +942,11 @@ static uae_u32 uaelib_host_get_platform(void) static uae_u32 uaelib_host_status(TrapContext* ctx, uae_u32 handle) { (void)ctx; -#if defined(_WIN32) - return HOST_SHELL_STATUS_INVALID; -#else if (shell_sessions.find(handle) == shell_sessions.end()) return HOST_SHELL_STATUS_INVALID; ShellSession& session = shell_sessions[handle]; return host_shell_update_status(session); -#endif } static std::string quote_path(const char* path) { @@ -1033,6 +1089,11 @@ static uae_u32 uaelib_midi(TrapContext *ctx, uae_u32 op, uae_u32 index, uaecptr static uae_u32 uaelib_demux_common(TrapContext *ctx, uae_u32 ARG0, uae_u32 ARG1, uae_u32 ARG2, uae_u32 ARG3, uae_u32 ARG4, uae_u32 ARG5) { write_log("%ld\n",ARG0); + +#ifdef AMIBERRY + if (!currprefs.native_code && uaelib_host_trap_requires_native_code(ARG0)) + return uaelib_host_trap_denied_result(ARG0); +#endif switch (ARG0) { case 0: return emulib_GetVersion(); @@ -1090,17 +1151,20 @@ static uae_u32 uaelib_demux_common(TrapContext *ctx, uae_u32 ARG0, uae_u32 ARG1, } #ifdef AMIBERRY case 88: - if (currprefs.native_code) return emulib_execute_on_host(ctx, ARG1); - return 0; - case 89: return uaelib_host_view(ctx, ARG1); - - case 90: return uaelib_host_open(ctx, ARG1); - case 91: return uaelib_host_read(ctx, ARG1, ARG2, ARG3); - case 92: return uaelib_host_write(ctx, ARG1, ARG2, ARG3); + case 89: + return uaelib_host_view(ctx, ARG1); + case 90: + return uaelib_host_open(ctx, ARG1); + case 91: + return uaelib_host_read(ctx, ARG1, ARG2, ARG3); + case 92: + return uaelib_host_write(ctx, ARG1, ARG2, ARG3); case 93: return uaelib_host_close(ctx, ARG1); - case 94: return uaelib_host_status(ctx, ARG1); - case 95: return uaelib_host_open_pipe(ctx, ARG1); + case 94: + return uaelib_host_status(ctx, ARG1); + case 95: + return uaelib_host_open_pipe(ctx, ARG1); case 96: return uaelib_host_get_platform(); case 100: