Piotr Caban : gdiplus: Make GpBitmap->bitmapbits access thread safe.

Alexandre Julliard julliard at winehq.org
Thu Feb 16 15:12:28 CST 2017


Module: wine
Branch: master
Commit: 0eaaa1514454d584eb6638e0c7a31bb64bbc773b
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=0eaaa1514454d584eb6638e0c7a31bb64bbc773b

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Tue Feb 14 10:24:36 2017 +0100

gdiplus: Make GpBitmap->bitmapbits access thread safe.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/gdiplus/gdiplus_private.h | 14 ++++++++++++
 dlls/gdiplus/image.c           | 51 ++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index b44340f..2e98065 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -348,6 +348,7 @@ struct GpImage{
     UINT frame_count, current_frame;
     ColorPalette *palette;
     REAL xres, yres;
+    LONG busy;
 };
 
 struct GpMetafile{
@@ -515,4 +516,17 @@ GpStatus gdip_format_string(HDC hdc,
 
 void get_log_fontW(const GpFont *, GpGraphics *, LOGFONTW *) DECLSPEC_HIDDEN;
 
+static inline BOOL image_lock(GpImage *image, BOOL *unlock)
+{
+    LONG tid = GetCurrentThreadId(), owner_tid;
+    owner_tid = InterlockedCompareExchange(&image->busy, tid, 0);
+    *unlock = !owner_tid;
+    return !owner_tid || owner_tid==tid;
+}
+
+static inline void image_unlock(GpImage *image, BOOL unlock)
+{
+    if (unlock) image->busy = 0;
+}
+
 #endif
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index 21d5a3a..4de8ecc 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -1027,16 +1027,22 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
     INT bitspp = PIXELFORMATBPP(format);
     GpRect act_rect; /* actual rect to be used */
     GpStatus stat;
+    BOOL unlock;
 
     TRACE("%p %p %d 0x%x %p\n", bitmap, rect, flags, format, lockeddata);
 
     if(!lockeddata || !bitmap)
         return InvalidParameter;
+    if(!image_lock(&bitmap->image, &unlock))
+        return ObjectBusy;
 
     if(rect){
         if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
           (rect->Y + rect->Height > bitmap->height) || !flags)
+        {
+            image_unlock(&bitmap->image, unlock);
             return InvalidParameter;
+        }
 
         act_rect = *rect;
     }
@@ -1049,6 +1055,7 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
     if(bitmap->lockmode)
     {
         WARN("bitmap is already locked and cannot be locked again\n");
+        image_unlock(&bitmap->image, unlock);
         return WrongState;
     }
 
@@ -1066,6 +1073,7 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
         bitmap->lockmode = flags | ImageLockModeRead;
         bitmap->numlocks++;
 
+        image_unlock(&bitmap->image, unlock);
         return Ok;
     }
 
@@ -1076,6 +1084,7 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
         if (stat == NotImplemented)
         {
             FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format);
+            image_unlock(&bitmap->image, unlock);
             return NotImplemented;
         }
     }
@@ -1088,6 +1097,7 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
         if (stat == NotImplemented)
         {
             FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format);
+            image_unlock(&bitmap->image, unlock);
             return NotImplemented;
         }
     }
@@ -1103,7 +1113,11 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
 
         bitmap->bitmapbits = heap_alloc_zero(lockeddata->Stride * act_rect.Height);
 
-        if (!bitmap->bitmapbits) return OutOfMemory;
+        if (!bitmap->bitmapbits)
+        {
+            image_unlock(&bitmap->image, unlock);
+            return OutOfMemory;
+        }
 
         lockeddata->Scan0  = bitmap->bitmapbits;
     }
@@ -1128,6 +1142,7 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
         {
             heap_free(bitmap->bitmapbits);
             bitmap->bitmapbits = NULL;
+            image_unlock(&bitmap->image, unlock);
             return stat;
         }
     }
@@ -1137,6 +1152,7 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
     bitmap->lockx = act_rect.X;
     bitmap->locky = act_rect.Y;
 
+    image_unlock(&bitmap->image, unlock);
     return Ok;
 }
 
@@ -1158,14 +1174,20 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
 {
     GpStatus stat;
     static BOOL fixme = FALSE;
+    BOOL unlock;
 
     TRACE("(%p,%p)\n", bitmap, lockeddata);
 
     if(!bitmap || !lockeddata)
         return InvalidParameter;
+    if(!image_lock(&bitmap->image, &unlock))
+        return ObjectBusy;
 
     if(!bitmap->lockmode)
+    {
+        image_unlock(&bitmap->image, unlock);
         return WrongState;
+    }
 
     if(!(lockeddata->Reserved & ImageLockModeWrite)){
         if(!(--bitmap->numlocks))
@@ -1173,6 +1195,7 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
 
         heap_free(bitmap->bitmapbits);
         bitmap->bitmapbits = NULL;
+        image_unlock(&bitmap->image, unlock);
         return Ok;
     }
 
@@ -1181,6 +1204,7 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
         /* we passed a direct reference; no need to do anything */
         bitmap->lockmode = 0;
         bitmap->numlocks = 0;
+        image_unlock(&bitmap->image, unlock);
         return Ok;
     }
 
@@ -1206,6 +1230,7 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
     bitmap->lockmode = 0;
     bitmap->numlocks = 0;
 
+    image_unlock(&bitmap->image, unlock);
     return stat;
 }
 
@@ -3746,6 +3771,7 @@ static GpStatus select_frame_wic(GpImage *image, UINT active_frame)
     if(status != Ok)
         return status;
 
+    new_image->busy = image->busy;
     memcpy(&new_image->format, &image->format, sizeof(GUID));
     free_image_data(image);
     if (image->type == ImageTypeBitmap)
@@ -4219,30 +4245,39 @@ GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *d
 {
     GpStatus stat;
     const struct image_codec *codec = NULL;
+    BOOL unlock;
 
     TRACE("(%p,%s,%u)\n", image, debugstr_guid(dimensionID), frame);
 
     if (!image || !dimensionID)
         return InvalidParameter;
+    if(!image_lock(image, &unlock))
+        return ObjectBusy;
 
     if (frame >= image->frame_count)
     {
         WARN("requested frame %u, but image has only %u\n", frame, image->frame_count);
+        image_unlock(image, unlock);
         return InvalidParameter;
     }
 
     if (image->type != ImageTypeBitmap && image->type != ImageTypeMetafile)
     {
         WARN("invalid image type %d\n", image->type);
+        image_unlock(image, unlock);
         return InvalidParameter;
     }
 
     if (image->current_frame == frame)
+    {
+        image_unlock(image, unlock);
         return Ok;
+    }
 
     if (!image->decoder)
     {
         TRACE("image doesn't have an associated decoder\n");
+        image_unlock(image, unlock);
         return Ok;
     }
 
@@ -4251,10 +4286,13 @@ GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *d
     if (stat != Ok)
     {
         WARN("can't find decoder info\n");
+        image_unlock(image, unlock);
         return stat;
     }
 
-    return codec->select_func(image, frame);
+    stat = codec->select_func(image, frame);
+    image_unlock(image, unlock);
+    return stat;
 }
 
 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
@@ -5264,11 +5302,14 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
     UINT x, y, width, height;
     BitmapData src_lock, dst_lock;
     GpStatus stat;
+    BOOL unlock;
 
     TRACE("(%p, %u)\n", image, type);
 
     if (!image)
         return InvalidParameter;
+    if (!image_lock(image, &unlock))
+        return ObjectBusy;
 
     rotate_90 = type&1;
     flip_x = (type&6) == 2 || (type&6) == 4;
@@ -5277,6 +5318,7 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
     if (image->type != ImageTypeBitmap)
     {
         FIXME("Not implemented for type %i\n", image->type);
+        image_unlock(image, unlock);
         return NotImplemented;
     }
 
@@ -5286,6 +5328,7 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
     if (bpp < 8)
     {
         FIXME("Not implemented for %i bit images\n", bpp);
+        image_unlock(image, unlock);
         return NotImplemented;
     }
 
@@ -5305,7 +5348,10 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
     stat = GdipCreateBitmapFromScan0(width, height, 0, bitmap->format, NULL, &new_bitmap);
 
     if (stat != Ok)
+    {
+        image_unlock(image, unlock);
         return stat;
+    }
 
     stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format, &src_lock);
 
@@ -5365,6 +5411,7 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
     else
         GdipDisposeImage(&new_bitmap->image);
 
+    image_unlock(image, unlock);
     return stat;
 }
 




More information about the wine-cvs mailing list