static PyObject *
docstr_fallback_to_converter_default_impl(PyObject *module, str a)
/*[clinic end generated code: output=ae24a9c6f60ee8a6 input=0cbe6a4d24bc2274]*/
+
+
+/*[clinic input]
+@critical_section
+test_critical_section
+[clinic start generated code]*/
+
+PyDoc_STRVAR(test_critical_section__doc__,
+"test_critical_section($module, /)\n"
+"--\n"
+"\n");
+
+#define TEST_CRITICAL_SECTION_METHODDEF \
+ {"test_critical_section", (PyCFunction)test_critical_section, METH_NOARGS, test_critical_section__doc__},
+
+static PyObject *
+test_critical_section_impl(PyObject *module);
+
+static PyObject *
+test_critical_section(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(module);
+ return_value = test_critical_section_impl(module);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
+}
+
+static PyObject *
+test_critical_section_impl(PyObject *module)
+/*[clinic end generated code: output=9d5a87bb28aa3f0c input=8c58956d6ff00f80]*/
+
+
+/*[clinic input]
+@critical_section
+test_critical_section_meth_o
+ a: object(subclass_of="&PyUnicode_Type")
+ /
+[clinic start generated code]*/
+
+PyDoc_STRVAR(test_critical_section_meth_o__doc__,
+"test_critical_section_meth_o($module, a, /)\n"
+"--\n"
+"\n");
+
+#define TEST_CRITICAL_SECTION_METH_O_METHODDEF \
+ {"test_critical_section_meth_o", (PyCFunction)test_critical_section_meth_o, METH_O, test_critical_section_meth_o__doc__},
+
+static PyObject *
+test_critical_section_meth_o_impl(PyObject *module, PyObject *a);
+
+static PyObject *
+test_critical_section_meth_o(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ PyObject *a;
+
+ if (!PyUnicode_Check(arg)) {
+ _PyArg_BadArgument("test_critical_section_meth_o", "argument", "str", arg);
+ goto exit;
+ }
+ a = arg;
+ Py_BEGIN_CRITICAL_SECTION(module);
+ return_value = test_critical_section_meth_o_impl(module, a);
+ Py_END_CRITICAL_SECTION();
+
+exit:
+ return return_value;
+}
+
+static PyObject *
+test_critical_section_meth_o_impl(PyObject *module, PyObject *a)
+/*[clinic end generated code: output=7a9d7420802d1202 input=376533f51eceb6c3]*/
# The C statements required to clean up after the impl call.
self.cleanup: list[str] = []
+ # The C statements to generate critical sections (per-object locking).
+ self.lock: list[str] = []
+ self.unlock: list[str] = []
+
class FormatCounterFormatter(string.Formatter):
"""
condition=include.condition)
has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
- default_return_converter = f.return_converter.type == 'PyObject *'
+ simple_return = (f.return_converter.type == 'PyObject *'
+ and not f.critical_section)
new_or_init = f.kind.new_or_init
vararg: int | str = NO_VARARG
""") + "\n"
finale = normalize_snippet("""
{modifications}
+ {lock}
{return_value} = {c_basename}_impl({impl_arguments});
+ {unlock}
{return_conversion}
{post_parsing}
flags = "METH_METHOD|METH_FASTCALL|METH_KEYWORDS"
parser_prototype = self.PARSER_PROTOTYPE_DEF_CLASS
- return_error = ('return NULL;' if default_return_converter
+ return_error = ('return NULL;' if simple_return
else 'goto exit;')
parser_code = [normalize_snippet("""
if (nargs) {{
}}
""" % return_error, indent=4)]
- if default_return_converter:
+ if simple_return:
parser_definition = '\n'.join([
parser_prototype,
'{{',
converters[0].format_unit == 'O'):
meth_o_prototype = self.METH_O_PROTOTYPE
- if default_return_converter:
+ if simple_return:
# maps perfectly to METH_O, doesn't need a return converter.
# so we skip making a parse function
# and call directly into the impl function.
selfless = parameters[1:]
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();')
+
last_group = 0
first_optional = len(selfless)
positional = selfless and selfless[-1].is_positional_only()
template_dict['post_parsing'] = format_escape("".join(data.post_parsing).rstrip())
template_dict['cleanup'] = format_escape("".join(data.cleanup))
template_dict['return_value'] = data.return_value
+ template_dict['lock'] = "\n".join(data.lock)
+ template_dict['unlock'] = "\n".join(data.unlock)
# used by unpack tuple code generator
unpack_min = first_optional
modifications=template_dict['modifications'],
post_parsing=template_dict['post_parsing'],
cleanup=template_dict['cleanup'],
+ lock=template_dict['lock'],
+ unlock=template_dict['unlock'],
)
# Only generate the "exit:" label
# functions with optional groups because we can't represent
# those accurately with inspect.Signature in 3.4.
docstring_only: bool = False
+ critical_section: bool = False
def __post_init__(self) -> None:
self.parent = self.cls or self.module
coexist: bool
parameter_continuation: str
preserve_output: bool
+ critical_section: bool
from_version_re = re.compile(r'([*/]) +\[from +(.+)\]')
def __init__(self, clinic: Clinic) -> None:
self.forced_text_signature: str | None = None
self.parameter_continuation = ''
self.preserve_output = False
+ self.critical_section = False
def directive_version(self, required: str) -> None:
global version
fail("Can't set @classmethod, function is not a normal callable")
self.kind = CLASS_METHOD
+ def at_critical_section(self) -> None:
+ self.critical_section = True
+
def at_staticmethod(self) -> None:
if self.kind is not CALLABLE:
fail("Can't set @staticmethod, function is not a normal callable")
return_converter = CReturnConverter()
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)
+ return_converter=return_converter, kind=self.kind, coexist=self.coexist,
+ critical_section=self.critical_section)
self.block.signatures.append(self.function)
# insert a self converter automatically