Commit 6867f6189fa31bd22d623d87367975f830f14a46

Ryan C. Gordon 2018-02-16T14:56:28

video: put a spinlock around a global linked list. This should only contend if you're allocating or freeing surfaces from multiple threads at once, and then just for a short time. Fixes Bugzilla #4084.

diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c
index 5dacf53..2e26395 100644
--- a/src/video/SDL_pixels.c
+++ b/src/video/SDL_pixels.c
@@ -490,16 +490,20 @@ SDL_MasksToPixelFormatEnum(int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
 }
 
 static SDL_PixelFormat *formats;
+static SDL_SpinLock formats_lock = 0;
 
 SDL_PixelFormat *
 SDL_AllocFormat(Uint32 pixel_format)
 {
     SDL_PixelFormat *format;
 
+    SDL_AtomicLock(&formats_lock);
+
     /* Look it up in our list of previously allocated formats */
     for (format = formats; format; format = format->next) {
         if (pixel_format == format->format) {
             ++format->refcount;
+            SDL_AtomicUnlock(&formats_lock);
             return format;
         }
     }
@@ -507,10 +511,12 @@ SDL_AllocFormat(Uint32 pixel_format)
     /* Allocate an empty pixel format structure, and initialize it */
     format = SDL_malloc(sizeof(*format));
     if (format == NULL) {
+        SDL_AtomicUnlock(&formats_lock);
         SDL_OutOfMemory();
         return NULL;
     }
     if (SDL_InitFormat(format, pixel_format) < 0) {
+        SDL_AtomicUnlock(&formats_lock);
         SDL_free(format);
         SDL_InvalidParamError("format");
         return NULL;
@@ -521,6 +527,9 @@ SDL_AllocFormat(Uint32 pixel_format)
         format->next = formats;
         formats = format;
     }
+
+    SDL_AtomicUnlock(&formats_lock);
+
     return format;
 }
 
@@ -598,7 +607,11 @@ SDL_FreeFormat(SDL_PixelFormat *format)
         SDL_InvalidParamError("format");
         return;
     }
+
+    SDL_AtomicLock(&formats_lock);
+
     if (--format->refcount > 0) {
+        SDL_AtomicUnlock(&formats_lock);
         return;
     }
 
@@ -614,6 +627,8 @@ SDL_FreeFormat(SDL_PixelFormat *format)
         }
     }
 
+    SDL_AtomicUnlock(&formats_lock);
+
     if (format->palette) {
         SDL_FreePalette(format->palette);
     }