Commits

ecsv  committed f259cbe

Reduce pause when saving to native mupen64plus savestates

  • Participants
  • Parent commits 504938c

Comments (0)

Files changed (4)

File src/api/frontend.c

     plugin_connect(M64PLUGIN_INPUT, NULL);
     plugin_connect(M64PLUGIN_CORE, NULL);
 
+    savestates_init();
+
     /* next, start up the configuration handling code by loading and parsing the config file */
     if (ConfigInit(ConfigPath, DataPath) != M64ERR_SUCCESS)
         return M64ERR_INTERNAL;
     /* close down some core sub-systems */
     romdatabase_close();
     ConfigShutdown();
-    savestates_clear_job();
     workqueue_shutdown();
+    savestates_deinit();
 
     /* tell SDL to shut down */
     SDL_Quit();

File src/main/list.h

     return (head->next == head);
 }
 
-#define list_entry(ptr, type, member) \
+#define container_of(ptr, type, member) \
     ({ const typeof(((type*)0)->member) * __mptr = (ptr); \
      (type *)((char *)__mptr - offsetof(type, member)); })
 
+#define list_entry(ptr, type, member) container_of(ptr, type, member)
+
 #define list_first_entry(ptr, type, member) \
     list_entry((ptr)->next, type, member)
 

File src/main/savestates.c

 
 #include <stdlib.h>
 #include <string.h>
+#include <SDL_thread.h>
 
 #define M64P_CORE_PROTOTYPES 1
 #include "api/m64p_types.h"
 #include "main.h"
 #include "rom.h"
 #include "util.h"
+#include "workqueue.h"
 
 #include "memory/memory.h"
 #include "memory/flashram.h"
 static unsigned int slot = 0;
 static int autoinc_save_slot = 0;
 
+static SDL_mutex *savestates_lock;
+
+struct savestate_work {
+    char *filepath;
+    char *data;
+    size_t size;
+    struct work_struct work;
+};
+
 /* Returns the malloc'd full path of the currently selected savestate. */
 static char *savestates_generate_path(savestates_type type)
 {
         fname = strdup(fn);
 }
 
-void savestates_clear_job(void)
+static void savestates_clear_job(void)
 {
     savestates_set_job(savestates_job_nothing, savestates_type_unknown, NULL);
 }
     unsigned char *savestateData, *curr;
     char queue[1024];
 
+    SDL_LockMutex(savestates_lock);
+
     f = gzopen(filepath, "rb");
     if(f==NULL)
     {
         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not open state file: %s", filepath);
+        SDL_UnlockMutex(savestates_lock);
         return 0;
     }
 
     {
         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not read header from state file %s", filepath);
         gzclose(f);
+        SDL_UnlockMutex(savestates_lock);
         return 0;
     }
     curr = header;
     {
         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State file: %s is not a valid Mupen64plus savestate.", filepath);
         gzclose(f);
+        SDL_UnlockMutex(savestates_lock);
         return 0;
     }
     curr += 8;
     {
         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State version (%08x) isn't compatible. Please update Mupen64Plus.", version);
         gzclose(f);
+        SDL_UnlockMutex(savestates_lock);
         return 0;
     }
 
     {
         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State ROM MD5 does not match current ROM.");
         gzclose(f);
+        SDL_UnlockMutex(savestates_lock);
         return 0;
     }
     curr += 32;
     {
         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Insufficient memory to load state.");
         gzclose(f);
+        SDL_UnlockMutex(savestates_lock);
         return 0;
     }
     if (gzread(f, savestateData, savestateSize) != savestateSize ||
         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not read Mupen64Plus savestate data from %s", filepath);
         free(savestateData);
         gzclose(f);
+        SDL_UnlockMutex(savestates_lock);
         return 0;
     }
 
     gzclose(f);
+    SDL_UnlockMutex(savestates_lock);
 
     // Parse savestate
     rdram_register.rdram_config = GETDATA(curr, unsigned int);
     return ret;
 }
 
+static void savestates_save_m64p_work(struct work_struct *work)
+{
+    gzFile f;
+    struct savestate_work *save = container_of(work, struct savestate_work, work);
+
+    SDL_LockMutex(savestates_lock);
+
+    // Write the state to a GZIP file
+    f = gzopen(save->filepath, "wb");
+
+    if (f==NULL)
+    {
+        main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not open state file: %s", save->filepath);
+        free(save->data);
+        return;
+    }
+
+    if (gzwrite(f, save->data, save->size) != save->size)
+    {
+        main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not write data to state file: %s", save->filepath);
+        gzclose(f);
+        free(save->data);
+        return;
+    }
+
+    gzclose(f);
+    main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Saved state to: %s", namefrompath(save->filepath));
+    free(save->data);
+    free(save->filepath);
+    free(save);
+
+    SDL_UnlockMutex(savestates_lock);
+}
+
 static int savestates_save_m64p(char *filepath)
 {
     unsigned char outbuf[4];
-    gzFile f;
     int i;
 
     char queue[1024];
     int queuelength;
 
-    size_t savestateSize;
-    char *savestateData, *curr;
+    struct savestate_work *save;
+    char *curr;
+
+    save = malloc(sizeof(*save));
+    if (!save) {
+        main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Insufficient memory to save state.");
+        return 0;
+    }
+
+    save->filepath = strdup(filepath);
 
     if(autoinc_save_slot)
         savestates_inc_slot();
     queuelength = save_eventqueue_infos(queue);
 
     // Allocate memory for the save state data
-    savestateSize = 16788288 + queuelength;
-    savestateData = curr = malloc(savestateSize);
-    if (savestateData == NULL)
+    save->size = 16788288 + queuelength;
+    save->data = curr = malloc(save->size);
+    if (save->data == NULL)
     {
+        free(save->filepath);
+        free(save);
         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Insufficient memory to save state.");
         return 0;
     }
     to_little_endian_buffer(queue, 4, queuelength/4);
     PUTARRAY(queue, curr, char, queuelength);
 
-    // assert(curr == savestateData + savestateSize)
+    // assert(curr == save->data + save->size)
 
-    // Write the state to a GZIP file
-    f = gzopen(filepath, "wb");
+    init_work(&save->work, savestates_save_m64p_work);
+    queue_work(&save->work);
 
-    if (f==NULL)
-    {
-        main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not open state file: %s", filepath);
-        free(savestateData);
-        return 0;
-    }
-
-    if (gzwrite(f, savestateData, savestateSize) != savestateSize)
-    {
-        main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not write data to state file: %s", filepath);
-        gzclose(f);
-        free(savestateData);
-        return 0;
-    }
-
-    gzclose(f);
-    free(savestateData);
-    main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Saved state to: %s", namefrompath(filepath));
     return 1;
 }
 
     savestates_clear_job();
     return ret;
 }
+
+void savestates_init(void)
+{
+    savestates_lock = SDL_CreateMutex();
+    if (!savestates_lock) {
+        DebugMessage(M64MSG_ERROR, "Could not create savestates list lock");
+        return;
+    }
+}
+
+void savestates_deinit(void)
+{
+    SDL_DestroyMutex(savestates_lock);
+    savestates_clear_job();
+}

File src/main/savestates.h

 
 savestates_job savestates_get_job(void);
 void savestates_set_job(savestates_job j, savestates_type t, const char *fn);
-void savestates_clear_job(void);
+void savestates_init(void);
+void savestates_deinit(void);
 
 int savestates_load(void);
 int savestates_save(void);