Source

pygame / src / surflock.c

Diff from to

File src/surflock.c

 /*
   pygame - Python Game Library
   Copyright (C) 2000-2001  Pete Shinners
+  Copyright (C) 2008 Marcus von Appen
 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
 
 static int PySurface_Lock (PyObject* surfobj);
 static int PySurface_Unlock (PyObject* surfobj);
+static int PySurface_LockBy (PyObject* surfobj, PyObject* lockobj);
+static int PySurface_UnlockBy (PyObject* surfobj, PyObject* lockobj);
+
+static void _lifelock_dealloc (PyObject* self);
 
 static void
 PySurface_Prep (PyObject* surfobj)
     {
         SDL_Surface* surf = PySurface_AsSurface (surfobj);
         SDL_Surface* owner = PySurface_AsSurface (data->owner);
-        PySurface_Lock (data->owner);
+        PySurface_LockBy (data->owner, surfobj);
         surf->pixels = ((char*) owner->pixels) + data->pixeloffset;
     }
 }
 {
     struct SubSurface_Data* data = ((PySurfaceObject*) surfobj)->subsurface;
     if (data)
-        PySurface_Unlock (data->owner);
+        PySurface_UnlockBy (data->owner, surfobj);
 }
 
 static int
 PySurface_Lock (PyObject* surfobj)
 {
+    return PySurface_LockBy (surfobj, surfobj);
+}
+
+static int
+PySurface_Unlock (PyObject* surfobj)
+{
+    return PySurface_UnlockBy (surfobj, surfobj);
+}
+
+static int
+PySurface_LockBy (PyObject* surfobj, PyObject* lockobj)
+{
+    PyObject *ref;
     PySurfaceObject* surf = (PySurfaceObject*) surfobj;
+
+    if (!surf->locklist)
+    {
+        surf->locklist = PyList_New (0);
+        if (!surf->locklist)
+            return 0;
+    }
+    ref = PyWeakref_NewRef (lockobj, NULL);
+    if (!ref)
+        return 0;
+    if (ref == Py_None)
+    {
+        Py_DECREF (ref);
+        return 0;
+    }
+    PyList_Append (surf->locklist, ref);
+
     if (surf->subsurface)
         PySurface_Prep (surfobj);
     if (SDL_LockSurface (surf->surf) == -1)
 }
 
 static int
-PySurface_Unlock (PyObject* surfobj)
+PySurface_UnlockBy (PyObject* surfobj, PyObject* lockobj)
 {
     PySurfaceObject* surf = (PySurfaceObject*) surfobj;
-    if (surf->surf != NULL)
-        SDL_UnlockSurface (surf->surf);
-    if (surf->subsurface)
-        PySurface_Unprep (surfobj);
-    return 1;
+    int found = 0;
+    int noerror = 1;
+
+    if (surf->locklist)
+    {
+        PyObject *item, *ref;
+        Py_ssize_t len = PyList_Size (surf->locklist);
+        while (--len >= 0 && !found)
+        {
+            item = PyList_GetItem (surf->locklist, len);
+            ref = PyWeakref_GetObject (item);
+            if (ref == lockobj)
+            {
+                if (PySequence_DelItem (surf->locklist, len) == -1)
+                    return 0;
+                else
+                    found = 1;
+            }
+        }
+
+        /* Clear dead references */
+        len = PyList_Size (surf->locklist);
+        while (--len >= 0)
+        {
+            item = PyList_GetItem (surf->locklist, len);
+            ref = PyWeakref_GetObject (item);
+            if (ref == Py_None)
+            {
+                if (PySequence_DelItem (surf->locklist, len) == -1)
+                    noerror = 0;
+                else
+                    found++;
+            }
+        }
+    }
+
+    if (!found)
+        return noerror;
+
+    /* Release all found locks. */
+    while (found > 0)
+    {
+        if (surf->surf != NULL)
+            SDL_UnlockSurface (surf->surf);
+        if (surf->subsurface)
+            PySurface_Unprep (surfobj);
+        found--;
+    }
+
+    return noerror;
 }
 
-/* lifetimelock object internals */
-typedef struct
-{
-    PyObject_HEAD
-    PyObject* surface;
-} PyLifetimeLockObject;
-
-static void
-lifelock_dealloc (PyObject* self)
-{
-    PyLifetimeLockObject* lifelock = (PyLifetimeLockObject*) self;
-    
-    PySurface_Unlock (lifelock->surface);
-    Py_DECREF (lifelock->surface);
-    
-    PyObject_DEL (self);
-}
 
 static PyTypeObject PyLifetimeLock_Type =
 {
     PyObject_HEAD_INIT(NULL)
-    0,                           /*size*/
-    "SurfLifeLock",              /*name*/
-    sizeof(PyLifetimeLockObject),/*basic size*/
-    0,                           /*itemsize*/
-    lifelock_dealloc,            /*dealloc*/
+    0,                          /*size*/
+    "SurfLifeLock",             /*name*/
+    sizeof(PyLifetimeLock),     /*basic size*/
+    0,                          /* tp_itemsize */
+    _lifelock_dealloc,          /* tp_dealloc*/
+    0,                          /* tp_print */
+    0,                          /* tp_getattr */
+    0,                          /* tp_setattr */
+    0,                          /* tp_compare */
+    0,                          /* tp_repr */
+    0,                          /* tp_as_number */
+    0,                          /* tp_as_sequence */
+    0,                          /* tp_as_mapping */
+    0,                          /* tp_hash */
+    0,                          /* tp_call */
+    0,                          /* tp_str */
+    0,                          /* tp_getattro */
+    0,                          /* tp_setattro */
+    0,                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS,
+    0,                          /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    offsetof (PyLifetimeLock, weakrefs),  /* tp_weaklistoffset */
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    0,                          /* tp_methods */
+    0,                          /* tp_members */
+    0,                          /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    0,                          /* tp_dictoffset */
+    0,                          /* tp_init */
+    0,                          /* tp_alloc */
+    0,                          /* tp_new */
+    0,                          /* tp_free */
+    0,                          /* tp_is_gc */
+    0,                          /* tp_bases */
+    0,                          /* tp_mro */
+    0,                          /* tp_cache */
+    0,                          /* tp_subclasses */
+    0,                          /* tp_weaklist */
+    0                           /* tp_del */
 };
 
+/* lifetimelock object internals */
+static void
+_lifelock_dealloc (PyObject* self)
+{
+    PyLifetimeLock* lifelock = (PyLifetimeLock*) self;
+
+    if (lifelock->weakrefs)
+        PyObject_ClearWeakRefs (self);
+
+    PySurface_UnlockBy (lifelock->surface, lifelock->lockobj);
+    Py_DECREF (lifelock->surface);
+    PyObject_DEL (self);
+}
+
 static PyObject*
-PySurface_LockLifetime (PyObject* surf)
+PySurface_LockLifetime (PyObject* surfobj, PyObject *lockobj)
 {
-    PyLifetimeLockObject* life;
-    if (!surf)
+    PyLifetimeLock* life;
+    if (!surfobj)
         return RAISE (PyExc_SDLError, SDL_GetError ());
     
-    if (!PySurface_Lock (surf))
-        return NULL;
-    
-    life = PyObject_NEW (PyLifetimeLockObject, &PyLifetimeLock_Type);
+    life = PyObject_NEW (PyLifetimeLock, &PyLifetimeLock_Type);
     if (life)
     {
-        life->surface = surf;
-        Py_INCREF (surf);
+        life->surface = surfobj;
+        life->lockobj = lockobj;
+        life->weakrefs = NULL;
+        Py_INCREF (surfobj);
+        if (!PySurface_LockBy (surfobj, lockobj))
+            return NULL;
     }
     return (PyObject*) life;
 }
     dict = PyModule_GetDict (module);
     
     /* export the c api */
-    c_api[0] = PySurface_Prep;
-    c_api[1] = PySurface_Unprep;
-    c_api[2] = PySurface_Lock;
-    c_api[3] = PySurface_Unlock;
-    c_api[4] = PySurface_LockLifetime;
+    c_api[0] = &PyLifetimeLock_Type;
+    c_api[1] = PySurface_Prep;
+    c_api[2] = PySurface_Unprep;
+    c_api[3] = PySurface_Lock;
+    c_api[4] = PySurface_Unlock;
+    c_api[5] = PySurface_LockBy;
+    c_api[6] = PySurface_UnlockBy;
+    c_api[7] = PySurface_LockLifetime;
     apiobj = PyCObject_FromVoidPtr (c_api, NULL);
     PyDict_SetItemString (dict, PYGAMEAPI_LOCAL_ENTRY, apiobj);
     Py_DECREF (apiobj);