diff --git a/libretro-common/include/queues/task_queue.h b/libretro-common/include/queues/task_queue.h index 236d00e05d..aaed4ea30e 100644 --- a/libretro-common/include/queues/task_queue.h +++ b/libretro-common/include/queues/task_queue.h @@ -209,8 +209,10 @@ void task_queue_retrieve(task_retriever_data_t *data); void task_queue_check(void); /* Pushes a task - * The task will start as soon as possible. */ -void task_queue_push(retro_task_t *task); + * The task will start as soon as possible. + * If a second blocking task is attempted, false will be returned + * and the task will be ignored. */ +bool task_queue_push(retro_task_t *task); /* Blocks until all tasks have finished * will return early if cond is not NULL diff --git a/libretro-common/queues/task_queue.c b/libretro-common/queues/task_queue.c index 08961591e7..f0db3852e2 100644 --- a/libretro-common/queues/task_queue.c +++ b/libretro-common/queues/task_queue.c @@ -610,7 +610,7 @@ void task_queue_check(void) impl_current->gather(); } -void task_queue_push(retro_task_t *task) +bool task_queue_push(retro_task_t *task) { /* Ignore this task if a related one is already running */ if (task->type == TASK_TYPE_BLOCKING) @@ -634,12 +634,14 @@ void task_queue_push(retro_task_t *task) /* skip this task, user must try again later */ if (found) - return; + return false; } /* The lack of NULL checks in the following functions * is proposital to ensure correct control flow by the users. */ impl_current->push_running(task); + + return true; } void task_queue_wait(retro_task_condition_fn_t cond, void* data) diff --git a/tasks/task_save.c b/tasks/task_save.c index c4862a3cfc..55fb6e0de1 100644 --- a/tasks/task_save.c +++ b/tasks/task_save.c @@ -511,6 +511,8 @@ static void undo_save_state_cb(retro_task_t *task, void *task_data, void *user_data, const char *error) { + save_task_state_t *state = (save_task_state_t*)task_data; + /* Wipe the save file buffer as it's intended to be one use only */ undo_save_buf.path[0] = '\0'; undo_save_buf.size = 0; @@ -519,6 +521,8 @@ static void undo_save_state_cb(retro_task_t *task, free(undo_save_buf.data); undo_save_buf.data = NULL; } + + free(state); } /** @@ -563,6 +567,9 @@ void* get_serialized_data(const char *path, size_t serial_size) bool ret = false; void *data = NULL; + if (!serial_size) + return NULL; + data = malloc(serial_size); if (!data) @@ -576,12 +583,14 @@ void* get_serialized_data(const char *path, size_t serial_size) serial_info.data = data; serial_info.size = serial_size; ret = core_serialize(&serial_info); - if ( !ret ) + + if (!ret) { - free(data) ; - return NULL ; + free(data); + return NULL; } - return data ; + + return data; } /** @@ -607,7 +616,7 @@ static void task_save_handler(retro_task_t *task) } if (!state->data) - state->data = get_serialized_data(state->path, state->size) ; + state->data = get_serialized_data(state->path, state->size); remaining = MIN(state->size - state->written, SAVE_STATE_CHUNK); @@ -1054,6 +1063,7 @@ static void save_state_cb(retro_task_t *task, take_screenshot(path, true, state->has_valid_framebuffer, false, true); free(path); + free(state); } /** @@ -1089,7 +1099,16 @@ static void task_push_save_state(const char *path, void *data, size_t size, bool task->title = strdup(msg_hash_to_str(MSG_SAVING_STATE)); task->mute = state->mute; - task_queue_push(task); + if (!task_queue_push(task)) + { + /* Another blocking task is already active. */ + if (data) + free(data); + if (task->title) + task_free_title(task); + free(task); + free(state); + } return; @@ -1099,7 +1118,11 @@ error: if (state) free(state); if (task) + { + if (task->title) + task_free_title(task); free(task); + } } /** @@ -1163,7 +1186,16 @@ static void task_push_load_and_save_state(const char *path, void *data, task->title = strdup(msg_hash_to_str(MSG_LOADING_STATE)); task->mute = state->mute; - task_queue_push(task); + if (!task_queue_push(task)) + { + /* Another blocking task is already active. */ + if (data) + free(data); + if (task->title) + task_free_title(task); + free(task); + free(state); + } return; @@ -1194,13 +1226,13 @@ bool content_save_state(const char *path, bool save_to_disk, bool autosave) if (info.size == 0) return false; - if ( !save_state_in_background ) + if (!save_state_in_background) { RARCH_LOG("%s: \"%s\".\n", msg_hash_to_str(MSG_SAVING_STATE), path); - data = get_serialized_data(path, info.size) ; + data = get_serialized_data(path, info.size); if (!data) { @@ -1214,7 +1246,6 @@ bool content_save_state(const char *path, bool save_to_disk, bool autosave) msg_hash_to_str(MSG_STATE_SIZE), (int)info.size, msg_hash_to_str(MSG_BYTES)); - } if (save_to_disk) @@ -1234,15 +1265,15 @@ bool content_save_state(const char *path, bool save_to_disk, bool autosave) } else { - if ( data == NULL ) - data = get_serialized_data(path, info.size) ; + if (data == NULL) + data = get_serialized_data(path, info.size); - if ( data == NULL ) + if (data == NULL) { RARCH_ERR("%s \"%s\".\n", msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO), path); - return false ; + return false; } /* save_to_disk is false, which means we are saving the state in undo_load_buf to allow content_undo_load_state() to restore it */ @@ -1528,7 +1559,7 @@ bool event_save_files(void) { unsigned i; - cheat_manager_save_game_specific_cheats() ; + cheat_manager_save_game_specific_cheats(); if (!task_save_files || !rarch_ctl(RARCH_CTL_IS_SRAM_USED, NULL)) return false; @@ -1594,5 +1625,5 @@ void *savefile_ptr_get(void) void set_save_state_in_background(bool state) { - save_state_in_background = state ; + save_state_in_background = state; } diff --git a/tasks/task_screenshot.c b/tasks/task_screenshot.c index 7443e8dc2e..ba4c45aa29 100644 --- a/tasks/task_screenshot.c +++ b/tasks/task_screenshot.c @@ -49,6 +49,7 @@ #include "../retroarch.h" #include "../paths.h" #include "../msg_hash.h" +#include "../verbosity.h" #include "../gfx/video_driver.h" @@ -143,6 +144,9 @@ static void task_screenshot_handler(retro_task_t *task) { task_set_finished(task, true); + if (task->title) + task_free_title(task); + if (state->userbuf) free(state->userbuf); @@ -173,6 +177,9 @@ static void task_screenshot_handler(retro_task_t *task) runloop_msg_queue_push(msg, 1, state->is_paused ? 1 : 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); free(msg); } + + if (task->title) + task_free_title(task); } /* Take frame bottom-up. */ @@ -191,17 +198,19 @@ static bool screenshot_dump( char screenshot_path[PATH_MAX_LENGTH]; uint8_t *buf = NULL; settings_t *settings = config_get_ptr(); - retro_task_t *task = task_init(); - screenshot_task_state_t *state = (screenshot_task_state_t*) - calloc(1, sizeof(*state)); + retro_task_t *task; + screenshot_task_state_t *state; const char *screenshot_dir = settings->paths.directory_screenshot; struct retro_system_info system_info; - state->shotname[0] = '\0'; screenshot_path[0] = '\0'; if (!core_get_system_info(&system_info)) - return false; + return false; + + task = task_init(); + state = (screenshot_task_state_t*)calloc(1, sizeof(*state)); + state->shotname[0] = '\0'; /* If fullpath is true, name_base already contains a static path + filename to save the screenshot to. */ if (fullpath) @@ -282,10 +291,28 @@ static bool screenshot_dump( if (!savestate) task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); - task_queue_push(task); + if (!task_queue_push(task)) + { + /* There is already a blocking task going on */ + if (task->title) + task_free_title(task); + + free(task); + + if (state->out_buffer) + free(state->out_buffer); + + free(state); + + return false; + } } else + { + if (task) + free(task); return screenshot_dump_direct(state); + } return true; }