@@ -3610,6 +3610,45 @@ generic_pycdata_new(ctypes_state *st,
3610
3610
PyCFuncPtr_Type
3611
3611
*/
3612
3612
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
+
3613
3652
/*[clinic input]
3614
3653
@critical_section
3615
3654
@setter
@@ -3626,7 +3665,7 @@ _ctypes_CFuncPtr_errcheck_set_impl(PyCFuncPtrObject *self, PyObject *value)
3626
3665
return -1 ;
3627
3666
}
3628
3667
Py_XINCREF (value );
3629
- Py_XSETREF ( self -> errcheck , value );
3668
+ atomic_xsetref ( & self -> errcheck , value );
3630
3669
return 0 ;
3631
3670
}
3632
3671
@@ -3658,12 +3697,10 @@ static int
3658
3697
_ctypes_CFuncPtr_restype_set_impl (PyCFuncPtrObject * self , PyObject * value )
3659
3698
/*[clinic end generated code: output=0be0a086abbabf18 input=683c3bef4562ccc6]*/
3660
3699
{
3661
- PyObject * checker , * oldchecker ;
3700
+ PyObject * checker ;
3662
3701
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 );
3667
3704
return 0 ;
3668
3705
}
3669
3706
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)
3679
3716
if (PyObject_GetOptionalAttr (value , & _Py_ID (_check_retval_ ), & checker ) < 0 ) {
3680
3717
return -1 ;
3681
3718
}
3682
- oldchecker = self -> checker ;
3683
- self -> checker = checker ;
3684
3719
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 );
3687
3722
return 0 ;
3688
3723
}
3689
3724
@@ -3728,16 +3763,16 @@ _ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value)
3728
3763
PyObject * converters ;
3729
3764
3730
3765
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 );
3733
3768
} else {
3734
3769
ctypes_state * st = get_module_state_by_def (Py_TYPE (Py_TYPE (self )));
3735
3770
converters = converters_from_argtypes (st , value );
3736
3771
if (!converters )
3737
3772
return -1 ;
3738
- Py_XSETREF ( self -> converters , converters );
3773
+ atomic_xsetref ( & self -> converters , converters );
3739
3774
Py_INCREF (value );
3740
- Py_XSETREF ( self -> argtypes , value );
3775
+ atomic_xsetref ( & self -> argtypes , value );
3741
3776
}
3742
3777
return 0 ;
3743
3778
}
@@ -4533,16 +4568,11 @@ _build_result(PyObject *result, PyObject *callargs,
4533
4568
}
4534
4569
4535
4570
static PyObject *
4536
- PyCFuncPtr_call_lock_held (PyObject * op , PyObject * inargs , PyObject * kwds )
4571
+ PyCFuncPtr_call (PyObject * op , PyObject * inargs , PyObject * kwds )
4537
4572
{
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 ;
4546
4576
#ifdef MS_WIN32
4547
4577
IUnknown * piunk = NULL ;
4548
4578
#endif
@@ -4560,13 +4590,24 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4560
4590
}
4561
4591
assert (info ); /* Cannot be NULL for PyCFuncPtrObject instances */
4562
4592
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 );
4570
4611
4571
4612
pProc = * (void * * )self -> b_ptr ;
4572
4613
#ifdef MS_WIN32
@@ -4577,34 +4618,35 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4577
4618
if (!this ) {
4578
4619
PyErr_SetString (PyExc_ValueError ,
4579
4620
"native com method call without 'this' parameter" );
4580
- return NULL ;
4621
+ goto finally ;
4581
4622
}
4582
4623
if (!CDataObject_Check (st , this )) {
4583
4624
PyErr_SetString (PyExc_TypeError ,
4584
4625
"Expected a COM this pointer as first argument" );
4585
- return NULL ;
4626
+ goto finally ;
4586
4627
}
4587
4628
/* there should be more checks? No, in Python */
4588
4629
/* First arg is a pointer to an interface instance */
4589
4630
if (!this -> b_ptr || * (void * * )this -> b_ptr == NULL ) {
4590
4631
PyErr_SetString (PyExc_ValueError ,
4591
4632
"NULL COM pointer access" );
4592
- return NULL ;
4633
+ goto finally ;
4593
4634
}
4594
4635
piunk = * (IUnknown * * )this -> b_ptr ;
4595
4636
if (NULL == piunk -> lpVtbl ) {
4596
4637
PyErr_SetString (PyExc_ValueError ,
4597
4638
"COM method call without VTable" );
4598
- return NULL ;
4639
+ goto finally ;
4599
4640
}
4600
4641
pProc = ((void * * )piunk -> lpVtbl )[self -> index - 0x1000 ];
4601
4642
}
4602
4643
#endif
4603
4644
callargs = _build_callargs (st , self , argtypes ,
4604
4645
inargs , kwds ,
4605
4646
& outmask , & inoutmask , & numretvals );
4606
- if (callargs == NULL )
4607
- return NULL ;
4647
+ if (callargs == NULL ) {
4648
+ goto finally ;
4649
+ }
4608
4650
4609
4651
if (converters ) {
4610
4652
int required = Py_SAFE_DOWNCAST (PyTuple_GET_SIZE (converters ),
@@ -4623,7 +4665,7 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4623
4665
required ,
4624
4666
required == 1 ? "" : "s" ,
4625
4667
actual );
4626
- return NULL ;
4668
+ goto finally ;
4627
4669
}
4628
4670
} else if (required != actual ) {
4629
4671
Py_DECREF (callargs );
@@ -4632,7 +4674,7 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4632
4674
required ,
4633
4675
required == 1 ? "" : "s" ,
4634
4676
actual );
4635
- return NULL ;
4677
+ goto finally ;
4636
4678
}
4637
4679
}
4638
4680
@@ -4663,23 +4705,19 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4663
4705
if (v == NULL || v != callargs ) {
4664
4706
Py_DECREF (result );
4665
4707
Py_DECREF (callargs );
4666
- return v ;
4708
+ ret = v ;
4709
+ goto finally ;
4667
4710
}
4668
4711
Py_DECREF (v );
4669
4712
}
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 ;
4683
4721
}
4684
4722
4685
4723
static int
0 commit comments