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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
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);
}