@@ -3591,6 +3591,45 @@ generic_pycdata_new(ctypes_state *st,
3591
3591
PyCFuncPtr_Type
3592
3592
*/
3593
3593
3594
+ static inline void
3595
+ atomic_xsetref (PyObject * * field , PyObject * value )
3596
+ {
3597
+ #ifdef Py_GIL_DISABLED
3598
+ PyObject * old = * field ;
3599
+ _Py_atomic_store_ptr (field , value );
3600
+ Py_XDECREF (old );
3601
+ #else
3602
+ Py_XSETREF (* field , value );
3603
+ #endif
3604
+ }
3605
+ /*
3606
+ This function atomically loads the reference from *field, and
3607
+ tries to get a new reference to it. If the incref fails,
3608
+ it acquires critical section of obj and returns a new reference to the *field.
3609
+ In the general case, this avoids contention on acquiring the critical section.
3610
+ */
3611
+ static inline PyObject *
3612
+ atomic_xgetref (PyObject * obj , PyObject * * field )
3613
+ {
3614
+ #ifdef Py_GIL_DISABLED
3615
+ PyObject * value = _Py_atomic_load_ptr (field );
3616
+ if (value == NULL ) {
3617
+ return NULL ;
3618
+ }
3619
+ if (_Py_TryIncrefCompare (field , value )) {
3620
+ return value ;
3621
+ }
3622
+ Py_BEGIN_CRITICAL_SECTION (obj );
3623
+ value = Py_XNewRef (* field );
3624
+ Py_END_CRITICAL_SECTION ();
3625
+ return value ;
3626
+ #else
3627
+ return Py_XNewRef (* field );
3628
+ #endif
3629
+ }
3630
+
3631
+
3632
+
3594
3633
/*[clinic input]
3595
3634
@critical_section
3596
3635
@setter
@@ -3607,7 +3646,7 @@ _ctypes_CFuncPtr_errcheck_set_impl(PyCFuncPtrObject *self, PyObject *value)
3607
3646
return -1 ;
3608
3647
}
3609
3648
Py_XINCREF (value );
3610
- Py_XSETREF ( self -> errcheck , value );
3649
+ atomic_xsetref ( & self -> errcheck , value );
3611
3650
return 0 ;
3612
3651
}
3613
3652
@@ -3639,12 +3678,10 @@ static int
3639
3678
_ctypes_CFuncPtr_restype_set_impl (PyCFuncPtrObject * self , PyObject * value )
3640
3679
/*[clinic end generated code: output=0be0a086abbabf18 input=683c3bef4562ccc6]*/
3641
3680
{
3642
- PyObject * checker , * oldchecker ;
3681
+ PyObject * checker ;
3643
3682
if (value == NULL ) {
3644
- oldchecker = self -> checker ;
3645
- self -> checker = NULL ;
3646
- Py_CLEAR (self -> restype );
3647
- Py_XDECREF (oldchecker );
3683
+ atomic_xsetref (& self -> restype , NULL );
3684
+ atomic_xsetref (& self -> checker , NULL );
3648
3685
return 0 ;
3649
3686
}
3650
3687
ctypes_state * st = get_module_state_by_def (Py_TYPE (Py_TYPE (self )));
@@ -3660,11 +3697,9 @@ _ctypes_CFuncPtr_restype_set_impl(PyCFuncPtrObject *self, PyObject *value)
3660
3697
if (PyObject_GetOptionalAttr (value , & _Py_ID (_check_retval_ ), & checker ) < 0 ) {
3661
3698
return -1 ;
3662
3699
}
3663
- oldchecker = self -> checker ;
3664
- self -> checker = checker ;
3665
3700
Py_INCREF (value );
3666
- Py_XSETREF ( self -> restype , value );
3667
- Py_XDECREF ( oldchecker );
3701
+ atomic_xsetref ( & self -> checker , checker );
3702
+ atomic_xsetref ( & self -> restype , value );
3668
3703
return 0 ;
3669
3704
}
3670
3705
@@ -3709,16 +3744,16 @@ _ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value)
3709
3744
PyObject * converters ;
3710
3745
3711
3746
if (value == NULL || value == Py_None ) {
3712
- Py_CLEAR ( self -> converters );
3713
- Py_CLEAR ( self -> argtypes );
3747
+ atomic_xsetref ( & self -> argtypes , NULL );
3748
+ atomic_xsetref ( & self -> converters , NULL );
3714
3749
} else {
3715
3750
ctypes_state * st = get_module_state_by_def (Py_TYPE (Py_TYPE (self )));
3716
3751
converters = converters_from_argtypes (st , value );
3717
3752
if (!converters )
3718
3753
return -1 ;
3719
- Py_XSETREF ( self -> converters , converters );
3754
+ atomic_xsetref ( & self -> converters , converters );
3720
3755
Py_INCREF (value );
3721
- Py_XSETREF ( self -> argtypes , value );
3756
+ atomic_xsetref ( & self -> argtypes , value );
3722
3757
}
3723
3758
return 0 ;
3724
3759
}
@@ -4514,16 +4549,11 @@ _build_result(PyObject *result, PyObject *callargs,
4514
4549
}
4515
4550
4516
4551
static PyObject *
4517
- PyCFuncPtr_call_lock_held (PyObject * op , PyObject * inargs , PyObject * kwds )
4552
+ PyCFuncPtr_call (PyObject * op , PyObject * inargs , PyObject * kwds )
4518
4553
{
4519
- _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (op );
4520
- PyObject * restype ;
4521
- PyObject * converters ;
4522
- PyObject * checker ;
4523
- PyObject * argtypes ;
4524
- PyObject * result ;
4525
- PyObject * callargs ;
4526
- PyObject * errcheck ;
4554
+ PyObject * result = NULL ;
4555
+ PyObject * callargs = NULL ;
4556
+ PyObject * ret = NULL ;
4527
4557
#ifdef MS_WIN32
4528
4558
IUnknown * piunk = NULL ;
4529
4559
#endif
@@ -4541,13 +4571,24 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4541
4571
}
4542
4572
assert (info ); /* Cannot be NULL for PyCFuncPtrObject instances */
4543
4573
4544
- restype = self -> restype ? self -> restype : info -> restype ;
4545
- converters = self -> converters ? self -> converters : info -> converters ;
4546
- checker = self -> checker ? self -> checker : info -> checker ;
4547
- argtypes = self -> argtypes ? self -> argtypes : info -> argtypes ;
4548
- /* later, we probably want to have an errcheck field in stginfo */
4549
- errcheck = self -> errcheck /* ? self->errcheck : info->errcheck */ ;
4550
-
4574
+ PyObject * restype = atomic_xgetref (op , & self -> restype );
4575
+ if (restype == NULL ) {
4576
+ restype = Py_XNewRef (info -> restype );
4577
+ }
4578
+ PyObject * converters = atomic_xgetref (op , & self -> converters );
4579
+ if (converters == NULL ) {
4580
+ converters = Py_XNewRef (info -> converters );
4581
+ }
4582
+ PyObject * checker = atomic_xgetref (op , & self -> checker );
4583
+ if (checker == NULL ) {
4584
+ checker = Py_XNewRef (info -> checker );
4585
+ }
4586
+ PyObject * argtypes = atomic_xgetref (op , & self -> argtypes );
4587
+ if (argtypes == NULL ) {
4588
+ argtypes = Py_XNewRef (info -> argtypes );
4589
+ }
4590
+ /* later, we probably want to have an errcheck field in stginfo */
4591
+ PyObject * errcheck = atomic_xgetref (op , & self -> errcheck );
4551
4592
4552
4593
pProc = * (void * * )self -> b_ptr ;
4553
4594
#ifdef MS_WIN32
@@ -4558,34 +4599,35 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4558
4599
if (!this ) {
4559
4600
PyErr_SetString (PyExc_ValueError ,
4560
4601
"native com method call without 'this' parameter" );
4561
- return NULL ;
4602
+ goto finally ;
4562
4603
}
4563
4604
if (!CDataObject_Check (st , this )) {
4564
4605
PyErr_SetString (PyExc_TypeError ,
4565
4606
"Expected a COM this pointer as first argument" );
4566
- return NULL ;
4607
+ goto finally ;
4567
4608
}
4568
4609
/* there should be more checks? No, in Python */
4569
4610
/* First arg is a pointer to an interface instance */
4570
4611
if (!this -> b_ptr || * (void * * )this -> b_ptr == NULL ) {
4571
4612
PyErr_SetString (PyExc_ValueError ,
4572
4613
"NULL COM pointer access" );
4573
- return NULL ;
4614
+ goto finally ;
4574
4615
}
4575
4616
piunk = * (IUnknown * * )this -> b_ptr ;
4576
4617
if (NULL == piunk -> lpVtbl ) {
4577
4618
PyErr_SetString (PyExc_ValueError ,
4578
4619
"COM method call without VTable" );
4579
- return NULL ;
4620
+ goto finally ;
4580
4621
}
4581
4622
pProc = ((void * * )piunk -> lpVtbl )[self -> index - 0x1000 ];
4582
4623
}
4583
4624
#endif
4584
4625
callargs = _build_callargs (st , self , argtypes ,
4585
4626
inargs , kwds ,
4586
4627
& outmask , & inoutmask , & numretvals );
4587
- if (callargs == NULL )
4588
- return NULL ;
4628
+ if (callargs == NULL ) {
4629
+ goto finally ;
4630
+ }
4589
4631
4590
4632
if (converters ) {
4591
4633
int required = Py_SAFE_DOWNCAST (PyTuple_GET_SIZE (converters ),
@@ -4604,7 +4646,7 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4604
4646
required ,
4605
4647
required == 1 ? "" : "s" ,
4606
4648
actual );
4607
- return NULL ;
4649
+ goto finally ;
4608
4650
}
4609
4651
} else if (required != actual ) {
4610
4652
Py_DECREF (callargs );
@@ -4613,7 +4655,7 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4613
4655
required ,
4614
4656
required == 1 ? "" : "s" ,
4615
4657
actual );
4616
- return NULL ;
4658
+ goto finally ;
4617
4659
}
4618
4660
}
4619
4661
@@ -4644,23 +4686,19 @@ PyCFuncPtr_call_lock_held(PyObject *op, PyObject *inargs, PyObject *kwds)
4644
4686
if (v == NULL || v != callargs ) {
4645
4687
Py_DECREF (result );
4646
4688
Py_DECREF (callargs );
4647
- return v ;
4689
+ ret = v ;
4690
+ goto finally ;
4648
4691
}
4649
4692
Py_DECREF (v );
4650
4693
}
4651
-
4652
- return _build_result (result , callargs ,
4653
- outmask , inoutmask , numretvals );
4654
- }
4655
-
4656
- static PyObject *
4657
- PyCFuncPtr_call (PyObject * op , PyObject * inargs , PyObject * kwds )
4658
- {
4659
- PyObject * result ;
4660
- Py_BEGIN_CRITICAL_SECTION (op );
4661
- result = PyCFuncPtr_call_lock_held (op , inargs , kwds );
4662
- Py_END_CRITICAL_SECTION ();
4663
- return result ;
4694
+ ret = _build_result (result , callargs , outmask , inoutmask , numretvals );
4695
+ finally :
4696
+ Py_XDECREF (restype );
4697
+ Py_XDECREF (converters );
4698
+ Py_XDECREF (checker );
4699
+ Py_XDECREF (argtypes );
4700
+ Py_XDECREF (errcheck );
4701
+ return ret ;
4664
4702
}
4665
4703
4666
4704
static int
0 commit comments