diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index da730c5b249..81f88c4d153 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -5542,3 +5542,173 @@ test_critical_section_meth_o(PyObject *module, PyObject *arg) static PyObject * test_critical_section_meth_o_impl(PyObject *module, PyObject *a) /*[clinic end generated code: output=7a9d7420802d1202 input=376533f51eceb6c3]*/ + +/*[clinic input] +@critical_section a +test_critical_section_object + a: object(subclass_of="&PyUnicode_Type") + / +test_critical_section_object +[clinic start generated code]*/ + +PyDoc_STRVAR(test_critical_section_object__doc__, +"test_critical_section_object($module, a, /)\n" +"--\n" +"\n" +"test_critical_section_object"); + +#define TEST_CRITICAL_SECTION_OBJECT_METHODDEF \ + {"test_critical_section_object", (PyCFunction)test_critical_section_object, METH_O, test_critical_section_object__doc__}, + +static PyObject * +test_critical_section_object_impl(PyObject *module, PyObject *a); + +static PyObject * +test_critical_section_object(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *a; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("test_critical_section_object", "argument", "str", arg); + goto exit; + } + a = arg; + Py_BEGIN_CRITICAL_SECTION(a); + return_value = test_critical_section_object_impl(module, a); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +static PyObject * +test_critical_section_object_impl(PyObject *module, PyObject *a) +/*[clinic end generated code: output=ec06df92232b0fb5 input=6f67f91b523c875f]*/ + +PyDoc_STRVAR(test_critical_section_object__doc__, +"test_critical_section_object($module, a, /)\n" +"--\n" +"\n" +"test_critical_section_object"); + +#define TEST_CRITICAL_SECTION_OBJECT_METHODDEF \ + {"test_critical_section_object", (PyCFunction)test_critical_section_object, METH_O, test_critical_section_object__doc__}, + +static PyObject * +test_critical_section_object_impl(PyObject *module, PyObject *a); + +static PyObject * +test_critical_section_object(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *a; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("test_critical_section_object", "argument", "str", arg); + goto exit; + } + a = arg; + Py_BEGIN_CRITICAL_SECTION(a); + return_value = test_critical_section_object_impl(module, a); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +/*[clinic input] +@critical_section a b +test_critical_section_object2 + a: object(subclass_of="&PyUnicode_Type") + b: object(subclass_of="&PyUnicode_Type") + / +test_critical_section_object2 +[clinic start generated code]*/ + +PyDoc_STRVAR(test_critical_section_object2__doc__, +"test_critical_section_object2($module, a, b, /)\n" +"--\n" +"\n" +"test_critical_section_object2"); + +#define TEST_CRITICAL_SECTION_OBJECT2_METHODDEF \ + {"test_critical_section_object2", _PyCFunction_CAST(test_critical_section_object2), METH_FASTCALL, test_critical_section_object2__doc__}, + +static PyObject * +test_critical_section_object2_impl(PyObject *module, PyObject *a, + PyObject *b); + +static PyObject * +test_critical_section_object2(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b; + + if (!_PyArg_CheckPositional("test_critical_section_object2", nargs, 2, 2)) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("test_critical_section_object2", "argument 1", "str", args[0]); + goto exit; + } + a = args[0]; + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("test_critical_section_object2", "argument 2", "str", args[1]); + goto exit; + } + b = args[1]; + Py_BEGIN_CRITICAL_SECTION2(a, b); + return_value = test_critical_section_object2_impl(module, a, b); + Py_END_CRITICAL_SECTION2(); + +exit: + return return_value; +} + +static PyObject * +test_critical_section_object2_impl(PyObject *module, PyObject *a, + PyObject *b) +/*[clinic end generated code: output=d73a1657c18df17a input=638824e41419a466]*/ + +PyDoc_STRVAR(test_critical_section_object2__doc__, +"test_critical_section_object2($module, a, b, /)\n" +"--\n" +"\n" +"test_critical_section_object2"); + +#define TEST_CRITICAL_SECTION_OBJECT2_METHODDEF \ + {"test_critical_section_object2", _PyCFunction_CAST(test_critical_section_object2), METH_FASTCALL, test_critical_section_object2__doc__}, + +static PyObject * +test_critical_section_object2_impl(PyObject *module, PyObject *a, + PyObject *b); + +static PyObject * +test_critical_section_object2(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b; + + if (!_PyArg_CheckPositional("test_critical_section_object2", nargs, 2, 2)) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("test_critical_section_object2", "argument 1", "str", args[0]); + goto exit; + } + a = args[0]; + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("test_critical_section_object2", "argument 2", "str", args[1]); + goto exit; + } + b = args[1]; + Py_BEGIN_CRITICAL_SECTION2(a, b); + return_value = test_critical_section_object2_impl(module, a, b); + Py_END_CRITICAL_SECTION2(); + +exit: + return return_value; +} diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index a205a5182ee..f9326c1b2ca 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1866,8 +1866,18 @@ def render_function( assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!" if f.critical_section: - data.lock.append('Py_BEGIN_CRITICAL_SECTION({self_name});') - data.unlock.append('Py_END_CRITICAL_SECTION();') + match len(f.target_critical_section): + case 0: + lock = 'Py_BEGIN_CRITICAL_SECTION({self_name});' + unlock = 'Py_END_CRITICAL_SECTION();' + case 1: + lock = 'Py_BEGIN_CRITICAL_SECTION({target_critical_section});' + unlock = 'Py_END_CRITICAL_SECTION();' + case _: + lock = 'Py_BEGIN_CRITICAL_SECTION2({target_critical_section});' + unlock = 'Py_END_CRITICAL_SECTION2();' + data.lock.append(lock) + data.unlock.append(unlock) last_group = 0 first_optional = len(selfless) @@ -1922,6 +1932,7 @@ def render_function( template_dict['docstring'] = self.docstring_for_c_string(f) template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = '' + template_dict['target_critical_section'] = ', '.join(f.target_critical_section) for converter in converters: converter.set_template_dict(template_dict) @@ -2970,6 +2981,7 @@ class Function: # those accurately with inspect.Signature in 3.4. docstring_only: bool = False critical_section: bool = False + target_critical_section: list[str] = dc.field(default_factory=list) def __post_init__(self) -> None: self.parent = self.cls or self.module @@ -5160,6 +5172,7 @@ def reset(self) -> None: self.parameter_continuation = '' self.preserve_output = False self.critical_section = False + self.target_critical_section: list[str] = [] def directive_version(self, required: str) -> None: global version @@ -5288,7 +5301,10 @@ def at_classmethod(self) -> None: fail("Can't set @classmethod, function is not a normal callable") self.kind = CLASS_METHOD - def at_critical_section(self) -> None: + def at_critical_section(self, *args: str) -> None: + if len(args) > 2: + fail("Up to 2 critical section variables are supported") + self.target_critical_section.extend(args) self.critical_section = True def at_staticmethod(self) -> None: @@ -5514,7 +5530,8 @@ def state_modulename_name(self, line: str) -> None: self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, return_converter=return_converter, kind=self.kind, coexist=self.coexist, - critical_section=self.critical_section) + critical_section=self.critical_section, + target_critical_section=self.target_critical_section) self.block.signatures.append(self.function) # insert a self converter automatically