@@ -3610,6 +3610,45 @@ generic_pycdata_new(ctypes_state *st,
36103610 PyCFuncPtr_Type
36113611*/
36123612
3613+ static inline void
3614+ atomic_xsetref (PyObject * * field , PyObject * value )
3615+ {
3616+ #ifdef Py_GIL_DISABLED
3617+ PyObject * old = * field ;
3618+ _Py_atomic_store_ptr (field , value );
3619+ Py_XDECREF (old );
3620+ #else
3621+ Py_XSETREF (* field , value );
3622+ #endif
3623+ }
3624+ /*
3625+ This function atomically loads the reference from *field, and
3626+ tries to get a new reference to it. If the incref fails,
3627+ it acquires critical section of obj and returns a new reference to the *field.
3628+ In the general case, this avoids contention on acquiring the critical section.
3629+ */
3630+ static inline PyObject *
3631+ atomic_xgetref (PyObject * obj , PyObject * * field )
3632+ {
3633+ #ifdef Py_GIL_DISABLED
3634+ PyObject * value = _Py_atomic_load_ptr (field );
3635+ if (value == NULL ) {
3636+ return NULL ;
3637+ }
3638+ if (_Py_TryIncrefCompare (field , value )) {
3639+ return value ;
3640+ }
3641+ Py_BEGIN_CRITICAL_SECTION (obj );
3642+ value = Py_XNewRef (* field );
3643+ Py_END_CRITICAL_SECTION ();
3644+ return value ;
3645+ #else
3646+ return Py_XNewRef (* field );
3647+ #endif
3648+ }
3649+
3650+
3651+
36133652/*[clinic input]
36143653@critical_section
36153654@setter
@@ -3626,7 +3665,7 @@ _ctypes_CFuncPtr_errcheck_set_impl(PyCFuncPtrObject *self, PyObject *value)
36263665 return -1 ;
36273666 }
36283667 Py_XINCREF (value );
3629- Py_XSETREF ( self -> errcheck , value );
3668+ atomic_xsetref ( & self -> errcheck , value );
36303669 return 0 ;
36313670}
36323671
@@ -3658,12 +3697,10 @@ static int
36583697_ctypes_CFuncPtr_restype_set_impl (PyCFuncPtrObject * self , PyObject * value )
36593698/*[clinic end generated code: output=0be0a086abbabf18 input=683c3bef4562ccc6]*/
36603699{
3661- PyObject * checker , * oldchecker ;
3700+ PyObject * checker ;
36623701 if (value == NULL ) {
3663- oldchecker = self -> checker ;
3664- self -> checker = NULL ;
3665- Py_CLEAR (self -> restype );
3666- Py_XDECREF (oldchecker );
3702+ atomic_xsetref (& self -> restype , NULL );
3703+ atomic_xsetref (& self -> checker , NULL );
36673704 return 0 ;
36683705 }
36693706 ctypes_state * st = get_module_state_by_def (Py_TYPE (Py_TYPE (self )));
@@ -3679,11 +3716,9 @@ _ctypes_CFuncPtr_restype_set_impl(PyCFuncPtrObject *self, PyObject *value)
36793716 if (PyObject_GetOptionalAttr (value , & _Py_ID (_check_retval_ ), & checker ) < 0 ) {
36803717 return -1 ;
36813718 }
3682- oldchecker = self -> checker ;
3683- self -> checker = checker ;
36843719 Py_INCREF (value );
3685- Py_XSETREF ( self -> restype , value );
3686- Py_XDECREF ( oldchecker );
3720+ atomic_xsetref ( & self -> checker , checker );
3721+ atomic_xsetref ( & self -> restype , value );
36873722 return 0 ;
36883723}
36893724
@@ -3728,16 +3763,16 @@ _ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value)
37283763 PyObject * converters ;
37293764
37303765 if (value == NULL || value == Py_None ) {
3731- Py_CLEAR ( self -> converters );
3732- Py_CLEAR ( self -> argtypes );
3766+ atomic_xsetref ( & self -> argtypes , NULL );
3767+ atomic_xsetref ( & self -> converters , NULL );
37333768 } else {
37343769 ctypes_state * st = get_module_state_by_def (Py_TYPE (Py_TYPE (self )));
37353770 converters = converters_from_argtypes (st , value );
37363771 if (!converters )
37373772 return -1 ;
3738- Py_XSETREF ( self -> converters , converters );
3773+ atomic_xsetref ( & self -> converters , converters );
37393774 Py_INCREF (value );
3740- Py_XSETREF ( self -> argtypes , value );
3775+ atomic_xsetref ( & self -> argtypes , value );
37413776 }
37423777 return 0 ;
37433778}
@@ -4533,16 +4568,11 @@ _build_result(PyObject *result, PyObject *callargs,
45334568}
45344569
45354570static PyObject *
4536- PyCFuncPtr_call_lock_held (PyObject * op , PyObject * inargs , PyObject * kwds )
4571+ PyCFuncPtr_call (PyObject * op , PyObject * inargs , PyObject * kwds )
45374572{
4538- _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (op );
4539- PyObject * restype ;
4540- PyObject * converters ;
4541- PyObject * checker ;
4542- PyObject * argtypes ;
4543- PyObject * result ;
4544- PyObject * callargs ;
4545- PyObject * errcheck ;
4573+ PyObject * result = NULL ;
4574+ PyObject * callargs = NULL ;
4575+ PyObject * ret = NULL ;
45464576#ifdef MS_WIN32
45474577 IUnknown * piunk = NULL ;
45484578#endif
@@ -4560,13 +4590,24 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
45604590 }
45614591 assert (info ); /* Cannot be NULL for PyCFuncPtrObject instances */
45624592
4563- restype = self -> restype ? self -> restype : info -> restype ;
4564- converters = self -> converters ? self -> converters : info -> converters ;
4565- checker = self -> checker ? self -> checker : info -> checker ;
4566- argtypes = self -> argtypes ? self -> argtypes : info -> argtypes ;
4567- /* later, we probably want to have an errcheck field in stginfo */
4568- errcheck = self -> errcheck /* ? self->errcheck : info->errcheck */ ;
4569-
4593+ PyObject * restype = atomic_xgetref (op , & self -> restype );
4594+ if (restype == NULL ) {
4595+ restype = Py_XNewRef (info -> restype );
4596+ }
4597+ PyObject * converters = atomic_xgetref (op , & self -> converters );
4598+ if (converters == NULL ) {
4599+ converters = Py_XNewRef (info -> converters );
4600+ }
4601+ PyObject * checker = atomic_xgetref (op , & self -> checker );
4602+ if (checker == NULL ) {
4603+ checker = Py_XNewRef (info -> checker );
4604+ }
4605+ PyObject * argtypes = atomic_xgetref (op , & self -> argtypes );
4606+ if (argtypes == NULL ) {
4607+ argtypes = Py_XNewRef (info -> argtypes );
4608+ }
4609+ /* later, we probably want to have an errcheck field in stginfo */
4610+ PyObject * errcheck = atomic_xgetref (op , & self -> errcheck );
45704611
45714612 pProc = * (void * * )self -> b_ptr ;
45724613#ifdef MS_WIN32
@@ -4577,34 +4618,35 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
45774618 if (!this ) {
45784619 PyErr_SetString (PyExc_ValueError ,
45794620 "native com method call without 'this' parameter" );
4580- return NULL ;
4621+ goto finally ;
45814622 }
45824623 if (!CDataObject_Check (st , this )) {
45834624 PyErr_SetString (PyExc_TypeError ,
45844625 "Expected a COM this pointer as first argument" );
4585- return NULL ;
4626+ goto finally ;
45864627 }
45874628 /* there should be more checks? No, in Python */
45884629 /* First arg is a pointer to an interface instance */
45894630 if (!this -> b_ptr || * (void * * )this -> b_ptr == NULL ) {
45904631 PyErr_SetString (PyExc_ValueError ,
45914632 "NULL COM pointer access" );
4592- return NULL ;
4633+ goto finally ;
45934634 }
45944635 piunk = * (IUnknown * * )this -> b_ptr ;
45954636 if (NULL == piunk -> lpVtbl ) {
45964637 PyErr_SetString (PyExc_ValueError ,
45974638 "COM method call without VTable" );
4598- return NULL ;
4639+ goto finally ;
45994640 }
46004641 pProc = ((void * * )piunk -> lpVtbl )[self -> index - 0x1000 ];
46014642 }
46024643#endif
46034644 callargs = _build_callargs (st , self , argtypes ,
46044645 inargs , kwds ,
46054646 & outmask , & inoutmask , & numretvals );
4606- if (callargs == NULL )
4607- return NULL ;
4647+ if (callargs == NULL ) {
4648+ goto finally ;
4649+ }
46084650
46094651 if (converters ) {
46104652 int required = Py_SAFE_DOWNCAST (PyTuple_GET_SIZE (converters ),
@@ -4623,7 +4665,7 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
46234665 required ,
46244666 required == 1 ? "" : "s" ,
46254667 actual );
4626- return NULL ;
4668+ goto finally ;
46274669 }
46284670 } else if (required != actual ) {
46294671 Py_DECREF (callargs );
@@ -4632,7 +4674,7 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
46324674 required ,
46334675 required == 1 ? "" : "s" ,
46344676 actual );
4635- return NULL ;
4677+ goto finally ;
46364678 }
46374679 }
46384680
@@ -4663,23 +4705,19 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
46634705 if (v == NULL || v != callargs ) {
46644706 Py_DECREF (result );
46654707 Py_DECREF (callargs );
4666- return v ;
4708+ ret = v ;
4709+ goto finally ;
46674710 }
46684711 Py_DECREF (v );
46694712 }
4670-
4671- return _build_result (result , callargs ,
4672- outmask , inoutmask , numretvals );
4673- }
4674-
4675- static PyObject *
4676- PyCFuncPtr_call (PyObject * op , PyObject * inargs , PyObject * kwds )
4677- {
4678- PyObject * result ;
4679- Py_BEGIN_CRITICAL_SECTION (op );
4680- result = PyCFuncPtr_call_lock_held (op , inargs , kwds );
4681- Py_END_CRITICAL_SECTION ();
4682- return result ;
4713+ ret = _build_result (result , callargs , outmask , inoutmask , numretvals );
4714+ finally :
4715+ Py_XDECREF (restype );
4716+ Py_XDECREF (converters );
4717+ Py_XDECREF (checker );
4718+ Py_XDECREF (argtypes );
4719+ Py_XDECREF (errcheck );
4720+ return ret ;
46834721}
46844722
46854723static int
0 commit comments