Commits

Trent Nelson committed f1d5b37 Draft

Improve (fix) type-override logic from previous commit.

- Handle GC types properly.
- Remove the temporary GetAttr/SetAttr etc wrappers in object.c
in lieu of new _PyObject_* counterparts in pyparallel.c that
are enabled once an object is protected.

  • Participants
  • Parent commits 99a1855
  • Branches px

Comments (0)

Files changed (4)

File Include/object.h

     size_t  px_flags;                   \
     void   *srw_lock;                   \
     void   *event;                      \
-    struct _typeobject *orig_type;      \
+    void   *orig_type;                  \
     struct _object *_ob_next;           \
     struct _object *_ob_prev;
 
 #define Py_REFCNT(ob)           (((PyObject*)(ob))->ob_refcnt)
 #define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)
 #define Py_ORIG_TYPE(ob)        (((PyObject*)(ob))->orig_type)
+#define Py_ORIG_TYPE_CAST(ob)   ((PyTypeObject *)(((PyObject*)(ob))->orig_type))
 #define Py_SIZE(ob)             (((PyVarObject*)(ob))->ob_size)
 
 /********************* String Literals ****************************************/

File Include/objimpl.h

 #ifndef WITH_PARALLEL
 #define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
 #else
-#define _Py_AS_GC(o) (Py_ISPX(o) ? (PyGC_Head *)0 : ((PyGC_Head *)(o)-1))
+#define _Py_AS_GC(o)   (Py_ISPX(o) ? (PyGC_Head *)0 : ((PyGC_Head *)(o)-1))
+#define _Py_FROM_GC(o) (Py_ISPX(o) ? (PyGC_Head *)0 : ((PyGC_Head *)(o)+1))
 #endif
 
 #define _PyGC_REFS_UNTRACKED                    (-2)

File Objects/object.c

     0,
     NULL,
     NULL,
+    NULL,
     &refchain,
     &refchain
 };
     return res;
 }
 
-#ifndef WITH_PARALLEL
 PyObject *
 PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
 {
     return _PyObject_GenericGetAttrWithDict(obj, name, NULL);
 }
-#else
-PyObject *
-PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
-{
-    if (!obj->px_flags & Py_PXFLAGS_RWLOCK)
-        return _PyObject_GenericGetAttrWithDict(obj, name, NULL);
-
-    AcquireSRWLockShared((PSRWLOCK)&(obj->srw_lock));
-    __try {
-        return _PyObject_GenericGetAttrWithDict(obj, name, NULL);
-    } __finally {
-        ReleaseSRWLockShared((PSRWLOCK)&(obj->srw_lock));
-    }
-}
-#endif
 
 int
 _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
     return res;
 }
 
-#ifndef WITH_PARALLEL
 int
 PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
 {
     return _PyObject_GenericSetAttrWithDict(obj, name, value, NULL);
 }
-#else
-int
-PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
-{
-    if (Py_ISPY(obj) && value->is_px == _Py_IS_PARALLEL) {
-        PyErr_SetString(
-            PyExc_ValueError,
-            "parallel object cannot be set to non-parallel object"
-        );
-        return -1;
-    }
-    if (!obj->px_flags & Py_PXFLAGS_RWLOCK)
-        return _PyObject_GenericSetAttrWithDict(obj, name, value, NULL);
-
-    AcquireSRWLockExclusive((PSRWLOCK)&(obj->srw_lock));
-    __try {
-        return _PyObject_GenericSetAttrWithDict(obj, name, value, NULL);
-    } __finally {
-        ReleaseSRWLockExclusive((PSRWLOCK)&(obj->srw_lock));
-    }
-}
-#endif
 
 int
 PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context)

File Python/pyparallel.c

 static PyObject *PyExc_WaitError;
 static PyObject *PyExc_WaitTimeoutError;
 
+int _PyObject_GenericSetAttr(PyObject *o, PyObject *n, PyObject *v);
+int _PyObject_SetAttrString(PyObject *, char *, PyObject *w);
+
+PyObject *_PyObject_GenericGetAttr(PyObject *o, PyObject *n);
+PyObject *_PyObject_GetAttrString(PyObject *, char *);
+
 __inline
 PyThreadState *
 get_main_thread_state(void)
     return active;
 }
 
-static void
+void
 _PyObject_Dealloc(PyObject *o)
 {
     PyTypeObject *tp;
+    destructor d;
 #ifdef Py_DEBUG
     Py_GUARD_OBJ(o);
     Py_GUARD
 #endif
     assert(Py_ORIG_TYPE(o));
-    assert(
-        Py_PXFLAGS(o) & (
-            Py_PXFLAGS_EVENT
-        )
-    );
 
     if (Py_HAS_EVENT(o))
         PyEvent_DESTROY(o);
 
     tp = Py_TYPE(o);
+    d = Py_ORIG_TYPE_CAST(o)->tp_dealloc;
     Py_TYPE(o) = Py_ORIG_TYPE(o);
     Py_ORIG_TYPE(o) = NULL;
-    (*Py_TYPE(o)->tp_dealloc)(o);
+    (*d)(o);
     PyMem_FREE(tp);
 }
 
 
 __inline
 PyObject *
-_protect(PyObject *obj)
-{
-    if (!_protected(obj)) {
-        InitializeSRWLock((PSRWLOCK)&(obj->srw_lock));
-        obj->px_flags |= Py_PXFLAGS_RWLOCK;
-    }
-    return obj;
-}
-
-PyObject *
-_async_protect(PyObject *self, PyObject *obj)
-{
-    Py_INCREF(obj);
-    if (Py_ISPX(obj)) {
-        PyErr_SetNone(PyExc_ProtectionError);
-        return NULL;
-    }
-    return _protect(obj);
-}
-
-__inline
-PyObject *
 _unprotect(PyObject *obj)
 {
     if (_protected(obj)) {
     Py_RETURN_BOOL(_try_write_lock(obj));
 }
 
+int
+_PyObject_GenericSetAttr(PyObject *o, PyObject *n, PyObject *v)
+{
+    int result;
+    assert(Py_ORIG_TYPE(o));
+    if (Py_HAS_RWLOCK(o))
+        _write_lock(o);
+    result = (*Py_ORIG_TYPE_CAST(o)->tp_setattro)(o, n, v);
+    if (Py_HAS_RWLOCK(o))
+        _write_unlock(o);
+
+    return result;
+}
+
+PyObject *
+_PyObject_GenericGetAttr(PyObject *o, PyObject *n)
+{
+    PyObject *result;
+    assert(Py_ORIG_TYPE(o));
+    if (Py_HAS_RWLOCK(o))
+        _read_lock(o);
+    result = (*Py_ORIG_TYPE_CAST(o)->tp_getattro)(o, n);
+    if (Py_HAS_RWLOCK(o))
+        _read_unlock(o);
+
+    return result;
+}
+
+int
+_PyObject_SetAttrString(PyObject *o, char *n, PyObject *v)
+{
+    int result;
+    assert(Py_ORIG_TYPE(o));
+    if (Py_HAS_RWLOCK(o))
+        _write_lock(o);
+    result = (*Py_ORIG_TYPE_CAST(o)->tp_setattr)(o, n, v);
+    if (Py_HAS_RWLOCK(o))
+        _write_unlock(o);
+    return result;
+}
+
+PyObject *
+_PyObject_GetAttrString(PyObject *o, char *n)
+{
+    PyObject *result;
+    assert(Py_ORIG_TYPE(o));
+    if (Py_HAS_RWLOCK(o))
+        _read_lock(o);
+    result = (*Py_ORIG_TYPE_CAST(o)->tp_getattr)(o, n);
+    if (Py_HAS_RWLOCK(o))
+        _read_unlock(o);
+
+    return result;
+}
+
 char
 _PyObject_PrepOrigType(PyObject *o)
 {
-    PyTypeObject *tp = Py_ORIG_TYPE(o);
-    if (!tp) {
-        tp = (PyTypeObject *)PyMem_MALLOC(sizeof(PyTypeObject));
-        if (!tp) {
+    if (!Py_ORIG_TYPE(o)) {
+        PyTypeObject *type = Py_TYPE(o), *tp;
+        size_t size = sizeof(PyTypeObject);
+        void *offset = type;
+        void *m;
+        int is_gc = PyType_IS_GC(type);
+        int is_tracked = 0;
+
+        if (is_gc) {
+            size = sizeof(PyHeapTypeObject) + sizeof(PyGC_Head);
+            offset = _Py_AS_GC(Py_TYPE(o));
+            is_tracked = _PyObject_GC_IS_TRACKED(Py_TYPE(o));
+        }
+
+        m = PyMem_MALLOC(size);
+        if (!m) {
             PyErr_NoMemory();
             return 0;
         }
-        memcpy(tp, Py_TYPE(o), sizeof(PyTypeObject));
-        Py_ORIG_TYPE(o) = Py_TYPE(o);
+
+        if (is_tracked)
+            _PyObject_GC_UNTRACK(type);
+
+        memcpy(m, offset, size);
+
+        if (is_gc)
+            tp = (PyTypeObject *)_Py_FROM_GC(m);
+        else
+            tp = (PyTypeObject *)m;
+
+        if (is_tracked)
+            _PyObject_GC_TRACK(tp);
+
+        Py_ORIG_TYPE(o) = type;
         Py_TYPE(o) = tp;
-        tp->tp_dealloc = _PyObject_Dealloc;
+        tp->tp_dealloc  = _PyObject_Dealloc;
+        tp->tp_setattro = _PyObject_GenericSetAttr;
+        tp->tp_getattro = _PyObject_GenericGetAttr;
+        tp->tp_setattr  = _PyObject_SetAttrString;
+        tp->tp_getattr  = _PyObject_GetAttrString;
     }
 
     assert(Py_ORIG_TYPE(o));
-    assert(Py_ORIG_TYPE(o)->tp_dealloc);
-    assert(Py_ORIG_TYPE(o)->tp_dealloc != _PyObject_Dealloc);
-    assert(Py_TYPE(o)->tp_dealloc == _PyObject_Dealloc);
+    assert(Py_ORIG_TYPE_CAST(o)->tp_dealloc);
+    assert(Py_ORIG_TYPE_CAST(o)->tp_dealloc != _PyObject_Dealloc);
+    assert(Py_TYPE(o)->tp_dealloc  == _PyObject_Dealloc);
+    assert(Py_TYPE(o)->tp_setattro == _PyObject_GenericSetAttr);
+    assert(Py_TYPE(o)->tp_getattro == _PyObject_GenericGetAttr);
+    assert(Py_TYPE(o)->tp_setattr  == _PyObject_SetAttrString);
+    assert(Py_TYPE(o)->tp_getattr  == _PyObject_GetAttrString);
     return 1;
 }
 
     return result;
 }
 
+__inline
+PyObject *
+_protect(PyObject *obj)
+{
+    if (!_protected(obj)) {
+        if (!_PyObject_PrepOrigType(obj))
+            return NULL;
+        InitializeSRWLock((PSRWLOCK)&(obj->srw_lock));
+        obj->px_flags |= Py_PXFLAGS_RWLOCK;
+    }
+    return obj;
+}
+
+PyObject *
+_async_protect(PyObject *self, PyObject *obj)
+{
+    Py_INCREF(obj);
+    if (Py_ISPX(obj)) {
+        PyErr_SetNone(PyExc_ProtectionError);
+        return NULL;
+    }
+    return _protect(obj);
+}
 
 #ifdef Py_DEBUG
 int