mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 07:59:42 +00:00
Make auto-savestates not use the task queue (#16061)
Auto savestate (and its optional thumbnail) is generated on core unload (quit, netplay start, etc). This ends up using the task-queue, which in many cases deadlocks and/or causes a crash due to its asynchronous nature. Given that this is a state that must be generated before quiting or reloading the core, it makes no sense to use the task queue, it should be a synchronous job like for instance SRAM saving. This should fix #15248 (tested by @schmurtzm)
This commit is contained in:
parent
f200717b4c
commit
ab376eb669
@ -1278,7 +1278,7 @@ bool command_event_save_auto_state(void)
|
|||||||
".auto",
|
".auto",
|
||||||
sizeof(savestate_name_auto) - _len);
|
sizeof(savestate_name_auto) - _len);
|
||||||
|
|
||||||
if (content_save_state((const char*)savestate_name_auto, true, true))
|
if (content_auto_save_state((const char*)savestate_name_auto))
|
||||||
RARCH_LOG("%s \"%s\" %s.\n",
|
RARCH_LOG("%s \"%s\" %s.\n",
|
||||||
msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO),
|
msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO),
|
||||||
savestate_name_auto, "succeeded");
|
savestate_name_auto, "succeeded");
|
||||||
@ -1970,7 +1970,7 @@ bool command_event_main_state(unsigned cmd)
|
|||||||
settings->bools.frame_time_counter_reset_after_save_state;
|
settings->bools.frame_time_counter_reset_after_save_state;
|
||||||
|
|
||||||
if (cmd == CMD_EVENT_SAVE_STATE)
|
if (cmd == CMD_EVENT_SAVE_STATE)
|
||||||
content_save_state(state_path, true, false);
|
content_save_state(state_path, true);
|
||||||
else
|
else
|
||||||
content_save_state_to_ram();
|
content_save_state_to_ram();
|
||||||
|
|
||||||
|
@ -52,7 +52,10 @@ bool content_ram_state_to_file(const char *path);
|
|||||||
bool content_load_state(const char* path, bool load_to_backup_buffer, bool autoload);
|
bool content_load_state(const char* path, bool load_to_backup_buffer, bool autoload);
|
||||||
|
|
||||||
/* Save a state from memory to disk. */
|
/* Save a state from memory to disk. */
|
||||||
bool content_save_state(const char *path, bool save_to_disk, bool autosave);
|
bool content_save_state(const char *path, bool save_to_disk);
|
||||||
|
|
||||||
|
/* Save an automatic savestate to disk. */
|
||||||
|
bool content_auto_save_state(const char *path);
|
||||||
|
|
||||||
/* Check a ram state write to disk. */
|
/* Check a ram state write to disk. */
|
||||||
bool content_ram_state_pending(void);
|
bool content_ram_state_pending(void);
|
||||||
|
@ -227,7 +227,7 @@ bool content_undo_load_state(void)
|
|||||||
|
|
||||||
/* Swap the current state with the backup state. This way, we can undo
|
/* Swap the current state with the backup state. This way, we can undo
|
||||||
what we're undoing */
|
what we're undoing */
|
||||||
content_save_state("RAM", false, false);
|
content_save_state("RAM", false);
|
||||||
|
|
||||||
ret = content_deserialize_state(temp_data, temp_data_size);
|
ret = content_deserialize_state(temp_data, temp_data_size);
|
||||||
|
|
||||||
@ -1072,7 +1072,7 @@ static void content_load_state_cb(retro_task_t *task,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Backup the current state so we can undo this load */
|
/* Backup the current state so we can undo this load */
|
||||||
content_save_state("RAM", false, false);
|
content_save_state("RAM", false);
|
||||||
|
|
||||||
ret = content_deserialize_state(buf, size);
|
ret = content_deserialize_state(buf, size);
|
||||||
|
|
||||||
@ -1307,6 +1307,79 @@ static void task_push_load_and_save_state(const char *path, void *data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* content_auto_save_state:
|
||||||
|
* @path : path of saved state that shall be written to.
|
||||||
|
* Save a state from memory to disk. This is used for automatic saving right
|
||||||
|
* before a core unload/deinit or content closing. The save is a blocking
|
||||||
|
* operation (does not use the task queue).
|
||||||
|
*
|
||||||
|
* Returns: true if successful, false otherwise.
|
||||||
|
**/
|
||||||
|
bool content_auto_save_state(const char *path)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
void *serial_data = NULL;
|
||||||
|
size_t serial_size;
|
||||||
|
intfstream_t *file = NULL;
|
||||||
|
|
||||||
|
if (!core_info_current_supports_savestate())
|
||||||
|
{
|
||||||
|
RARCH_LOG("[State]: %s\n",
|
||||||
|
msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
serial_size = core_serialize_size();
|
||||||
|
|
||||||
|
if (serial_size == 0 || !path_is_valid(path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
serial_data = content_get_serialized_data(&serial_size);
|
||||||
|
if (!serial_data)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#if defined(HAVE_ZLIB)
|
||||||
|
if (settings->bools.savestate_file_compression)
|
||||||
|
file = intfstream_open_rzip_file(path, RETRO_VFS_FILE_ACCESS_WRITE);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
file = intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_WRITE,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
free(serial_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serial_size != (size_t)intfstream_write(file, serial_data, serial_size))
|
||||||
|
{
|
||||||
|
intfstream_close(file);
|
||||||
|
free(serial_data);
|
||||||
|
free(file);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
intfstream_close(file);
|
||||||
|
free(serial_data);
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
#ifdef HAVE_SCREENSHOTS
|
||||||
|
if (settings->bools.savestate_thumbnail_enable)
|
||||||
|
{
|
||||||
|
video_driver_state_t *video_st = video_state_get_ptr();
|
||||||
|
const char *dir_screenshot = settings->paths.directory_screenshot;
|
||||||
|
bool validfb = video_st->frame_cache_data &&
|
||||||
|
video_st->frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID;
|
||||||
|
|
||||||
|
take_screenshot(dir_screenshot, path, true, validfb, false, false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* content_save_state:
|
* content_save_state:
|
||||||
* @path : path of saved state that shall be written to.
|
* @path : path of saved state that shall be written to.
|
||||||
@ -1316,7 +1389,7 @@ static void task_push_load_and_save_state(const char *path, void *data,
|
|||||||
*
|
*
|
||||||
* Returns: true if successful, false otherwise.
|
* Returns: true if successful, false otherwise.
|
||||||
**/
|
**/
|
||||||
bool content_save_state(const char *path, bool save_to_disk, bool autosave)
|
bool content_save_state(const char *path, bool save_to_disk)
|
||||||
{
|
{
|
||||||
size_t serial_size;
|
size_t serial_size;
|
||||||
void *data = NULL;
|
void *data = NULL;
|
||||||
@ -1352,17 +1425,17 @@ bool content_save_state(const char *path, bool save_to_disk, bool autosave)
|
|||||||
|
|
||||||
if (save_to_disk)
|
if (save_to_disk)
|
||||||
{
|
{
|
||||||
if (path_is_valid(path) && !autosave)
|
if (path_is_valid(path))
|
||||||
{
|
{
|
||||||
/* Before overwriting the savestate file, load it into a buffer
|
/* Before overwriting the savestate file, load it into a buffer
|
||||||
to allow undo_save_state() to work */
|
to allow undo_save_state() to work */
|
||||||
/* TODO/FIXME - Use msg_hash_to_str here */
|
/* TODO/FIXME - Use msg_hash_to_str here */
|
||||||
RARCH_LOG("[State]: %s ...\n",
|
RARCH_LOG("[State]: %s ...\n",
|
||||||
msg_hash_to_str(MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER));
|
msg_hash_to_str(MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER));
|
||||||
task_push_load_and_save_state(path, data, serial_size, true, autosave);
|
task_push_load_and_save_state(path, data, serial_size, true, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
task_push_save_state(path, data, serial_size, autosave);
|
task_push_save_state(path, data, serial_size, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1613,7 +1686,7 @@ bool content_load_state_from_ram(void)
|
|||||||
|
|
||||||
/* Swap the current state with the backup state. This way, we can undo
|
/* Swap the current state with the backup state. This way, we can undo
|
||||||
what we're undoing */
|
what we're undoing */
|
||||||
content_save_state("RAM", false, false);
|
content_save_state("RAM", false);
|
||||||
|
|
||||||
ret = content_deserialize_state(temp_data, temp_data_size);
|
ret = content_deserialize_state(temp_data, temp_data_size);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user