diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index f393537141c076..4a27c691fd2d0e 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -856,6 +856,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(certfile)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(chain)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(check_same_thread)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cid)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(clamp)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(clear)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(close)); @@ -983,6 +984,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(flush)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fold)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(follow_symlinks)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(force)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(format)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(format_spec)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(frame_buffer)); @@ -1218,6 +1220,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(readline)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(readonly)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(real)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(recv)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reducer_override)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(registry)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(rel_tol)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index f4fde6142b9e82..c070bdcecfe11e 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -347,6 +347,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(certfile) STRUCT_FOR_ID(chain) STRUCT_FOR_ID(check_same_thread) + STRUCT_FOR_ID(cid) STRUCT_FOR_ID(clamp) STRUCT_FOR_ID(clear) STRUCT_FOR_ID(close) @@ -474,6 +475,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(flush) STRUCT_FOR_ID(fold) STRUCT_FOR_ID(follow_symlinks) + STRUCT_FOR_ID(force) STRUCT_FOR_ID(format) STRUCT_FOR_ID(format_spec) STRUCT_FOR_ID(frame_buffer) @@ -709,6 +711,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(readline) STRUCT_FOR_ID(readonly) STRUCT_FOR_ID(real) + STRUCT_FOR_ID(recv) STRUCT_FOR_ID(reducer_override) STRUCT_FOR_ID(registry) STRUCT_FOR_ID(rel_tol) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 5c0ec7dd547115..7ddf72103be12a 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -854,6 +854,7 @@ extern "C" { INIT_ID(certfile), \ INIT_ID(chain), \ INIT_ID(check_same_thread), \ + INIT_ID(cid), \ INIT_ID(clamp), \ INIT_ID(clear), \ INIT_ID(close), \ @@ -981,6 +982,7 @@ extern "C" { INIT_ID(flush), \ INIT_ID(fold), \ INIT_ID(follow_symlinks), \ + INIT_ID(force), \ INIT_ID(format), \ INIT_ID(format_spec), \ INIT_ID(frame_buffer), \ @@ -1216,6 +1218,7 @@ extern "C" { INIT_ID(readline), \ INIT_ID(readonly), \ INIT_ID(real), \ + INIT_ID(recv), \ INIT_ID(reducer_override), \ INIT_ID(registry), \ INIT_ID(rel_tol), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 1a7f1c13c6dd16..4c9a6d00b08e5d 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1176,6 +1176,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(cid); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(clamp); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -1684,6 +1688,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(force); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(format); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2624,6 +2632,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(recv); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(reducer_override); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c index 9c1f8615161275..25364c1a9a6675 100644 --- a/Modules/_interpchannelsmodule.c +++ b/Modules/_interpchannelsmodule.c @@ -2340,6 +2340,47 @@ channel_id_converter(PyObject *arg, void *ptr) return 1; } +/*[clinic input] +module _interpchannels +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=10a1a1ec55663e0b]*/ + + +/*[python input] + +class channel_id_arg_converter(CConverter): + type = 'int64_t' + converter = 'channel_id_arg_converter' + broken_limited_capi = True + + def parse_arg(self, argname, displayname, *, limited_capi): + assert not limited_capi + return self.format_code(""" + if (!{converter}(module, {argname}, &{paramname})) {{{{ + goto exit; + }}}} + """, + argname=argname, + converter=self.converter) + + +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=78e17eef989afa6b]*/ + +static int +channel_id_arg_converter(PyObject *module, PyObject *arg, void *ptr) +{ + int64_t *cid_ptr = ptr; + struct channel_id_converter_data cid_data = { + .module = module, + }; + int res = channel_id_converter(arg, &cid_data); + *cid_ptr = cid_data.cid; + return res; +} + +#include "clinic/_interpchannelsmodule.c.h" + static int newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels, int force, int resolve, channelid **res) @@ -2907,17 +2948,19 @@ clear_interpreter(void *data) } +/*[clinic input] +_interpchannels.create + unboundop as unboundarg: int = -1 + fallback as fallbackarg: int = -1 + +Create a new cross-interpreter channel and return a unique generated ID. +[clinic start generated code]*/ + static PyObject * -channelsmod_create(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_create_impl(PyObject *module, int unboundarg, + int fallbackarg) +/*[clinic end generated code: output=88ba00ef117e17ef input=94bb97f4c661517e]*/ { - static char *kwlist[] = {"unboundop", "fallback", NULL}; - int unboundarg = -1; - int fallbackarg = -1; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:create", kwlist, - &unboundarg, &fallbackarg)) - { - return NULL; - } struct _channeldefaults defaults = {0}; if (resolve_unboundop(unboundarg, UNBOUND_REPLACE, &defaults.unboundop) < 0) @@ -2932,10 +2975,10 @@ channelsmod_create(PyObject *self, PyObject *args, PyObject *kwds) int64_t cid = channel_create(&_globals.channels, defaults); if (cid < 0) { - (void)handle_channel_error(-1, self, cid); + (void)handle_channel_error(-1, module, cid); return NULL; } - module_state *state = get_module_state(self); + module_state *state = get_module_state(module); if (state == NULL) { return NULL; } @@ -2943,10 +2986,10 @@ channelsmod_create(PyObject *self, PyObject *args, PyObject *kwds) int err = newchannelid(state->ChannelIDType, cid, 0, &_globals.channels, 0, 0, &cidobj); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { assert(cidobj == NULL); err = channel_destroy(&_globals.channels, cid); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { // XXX issue a warning? } return NULL; @@ -2956,40 +2999,36 @@ channelsmod_create(PyObject *self, PyObject *args, PyObject *kwds) return (PyObject *)cidobj; } -PyDoc_STRVAR(channelsmod_create_doc, -"channel_create(unboundop) -> cid\n\ -\n\ -Create a new cross-interpreter channel and return a unique generated ID."); +/*[clinic input] +_interpchannels.destroy + cid: channel_id_arg + +Close and finalize the channel. + +Afterward attempts to use the channel will behave as though it +never existed. +[clinic start generated code]*/ static PyObject * -channelsmod_destroy(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_destroy_impl(PyObject *module, int64_t cid) +/*[clinic end generated code: output=2f92ece8ec3d22f7 input=b4850ab65379a8c9]*/ { - static char *kwlist[] = {"cid", NULL}; - int64_t cid; - struct channel_id_converter_data cid_data = { - .module = self, - }; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_destroy", kwlist, - channel_id_converter, &cid_data)) { - return NULL; - } - cid = cid_data.cid; - int err = channel_destroy(&_globals.channels, cid); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(channelsmod_destroy_doc, -"channel_destroy(cid)\n\ -\n\ -Close and finalize the channel. Afterward attempts to use the channel\n\ -will behave as though it never existed."); +/*[clinic input] +_interpchannels.list_all + +Return the list of all IDs for active channels. +[clinic start generated code]*/ static PyObject * -channelsmod_list_all(PyObject *self, PyObject *Py_UNUSED(ignored)) +_interpchannels_list_all_impl(PyObject *module) +/*[clinic end generated code: output=3e646332445200da input=045b11b5ca08573a]*/ { int64_t count = 0; struct channel_id_and_info *cids = @@ -3004,7 +3043,7 @@ channelsmod_list_all(PyObject *self, PyObject *Py_UNUSED(ignored)) if (ids == NULL) { goto finally; } - module_state *state = get_module_state(self); + module_state *state = get_module_state(module); if (state == NULL) { Py_DECREF(ids); ids = NULL; @@ -3016,7 +3055,7 @@ channelsmod_list_all(PyObject *self, PyObject *Py_UNUSED(ignored)) int err = newchannelid(state->ChannelIDType, cur->id, 0, &_globals.channels, 0, 0, (channelid **)&cidobj); - if (handle_channel_error(err, self, cur->id)) { + if (handle_channel_error(err, module, cur->id)) { assert(cidobj == NULL); Py_SETREF(ids, NULL); break; @@ -3039,31 +3078,27 @@ channelsmod_list_all(PyObject *self, PyObject *Py_UNUSED(ignored)) return ids; } -PyDoc_STRVAR(channelsmod_list_all_doc, -"channel_list_all() -> [cid]\n\ -\n\ -Return the list of all IDs for active channels."); +/*[clinic input] +_interpchannels.list_interpreters + cid: channel_id_arg + * + send: bool + +Return all interpreter IDs associated with an end of the channel. + +The 'send' argument should be a boolean indicating whether to use +the send or receive end. +[clinic start generated code]*/ static PyObject * -channelsmod_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_list_interpreters_impl(PyObject *module, int64_t cid, + int send) +/*[clinic end generated code: output=0b23e8b2eaa81c07 input=7b32414cb68934f8]*/ { - static char *kwlist[] = {"cid", "send", NULL}; - int64_t cid; /* Channel ID */ - struct channel_id_converter_data cid_data = { - .module = self, - }; - int send = 0; /* Send or receive end? */ int64_t interpid; PyObject *ids, *interpid_obj; PyInterpreterState *interp; - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "O&$p:channel_list_interpreters", - kwlist, channel_id_converter, &cid_data, &send)) { - return NULL; - } - cid = cid_data.cid; - ids = PyList_New(0); if (ids == NULL) { goto except; @@ -3075,7 +3110,7 @@ channelsmod_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds) assert(interpid >= 0); int res = channel_is_associated(&_globals.channels, cid, interpid, send); if (res < 0) { - (void)handle_channel_error(res, self, cid); + (void)handle_channel_error(res, module, cid); goto except; } if (res) { @@ -3101,37 +3136,27 @@ channelsmod_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds) return ids; } -PyDoc_STRVAR(channelsmod_list_interpreters_doc, -"channel_list_interpreters(cid, *, send) -> [id]\n\ -\n\ -Return the list of all interpreter IDs associated with an end of the channel.\n\ -\n\ -The 'send' argument should be a boolean indicating whether to use the send or\n\ -receive end."); +/*[clinic input] +_interpchannels.send + cid: channel_id_arg + obj: object + unboundop as unboundarg: int = -1 + fallback as fallbackarg: int = -1 + * + blocking: bool = True + timeout as timeout_obj: object = None +Add the object's data to the channel's queue. + +By default, this waits for the object to be received. +[clinic start generated code]*/ static PyObject * -channelsmod_send(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_send_impl(PyObject *module, int64_t cid, PyObject *obj, + int unboundarg, int fallbackarg, int blocking, + PyObject *timeout_obj) +/*[clinic end generated code: output=85962ea2f04dbe70 input=a385e5dd91f5f1bb]*/ { - static char *kwlist[] = {"cid", "obj", "unboundop", "fallback", - "blocking", "timeout", NULL}; - struct channel_id_converter_data cid_data = { - .module = self, - }; - PyObject *obj; - int unboundarg = -1; - int fallbackarg = -1; - int blocking = 1; - PyObject *timeout_obj = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&O|ii$pO:channel_send", kwlist, - channel_id_converter, &cid_data, &obj, - &unboundarg, &fallbackarg, - &blocking, &timeout_obj)) - { - return NULL; - } - int64_t cid = cid_data.cid; PY_TIMEOUT_T timeout; if (PyThread_ParseTimeoutArg(timeout_obj, blocking, &timeout) < 0) { return NULL; @@ -3139,7 +3164,7 @@ channelsmod_send(PyObject *self, PyObject *args, PyObject *kwds) struct _channeldefaults defaults = {-1, -1}; if (unboundarg < 0 || fallbackarg < 0) { int err = channel_get_defaults(&_globals.channels, cid, &defaults); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } } @@ -3162,41 +3187,35 @@ channelsmod_send(PyObject *self, PyObject *args, PyObject *kwds) err = channel_send( &_globals.channels, cid, obj, NULL, unboundop, fallback); } - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(channelsmod_send_doc, -"channel_send(cid, obj, *, blocking=True, timeout=None)\n\ -\n\ -Add the object's data to the channel's queue.\n\ -By default this waits for the object to be received."); +/*[clinic input] +_interpchannels.send_buffer + cid: channel_id_arg + obj: object + unboundop as unboundarg: int = -1 + fallback as fallbackarg: int = -1 + * + blocking: bool = True + timeout as timeout_obj: object = None + +Add the object's buffer to the channel's queue. + +By default, this waits for the object to be received. +[clinic start generated code]*/ static PyObject * -channelsmod_send_buffer(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_send_buffer_impl(PyObject *module, int64_t cid, + PyObject *obj, int unboundarg, + int fallbackarg, int blocking, + PyObject *timeout_obj) +/*[clinic end generated code: output=f9937d0202c3972f input=c4fa2fcfa2ea07d6]*/ { - static char *kwlist[] = {"cid", "obj", "unboundop", "fallback", - "blocking", "timeout", NULL}; - struct channel_id_converter_data cid_data = { - .module = self, - }; - PyObject *obj; - int unboundarg = -1; - int fallbackarg = -1; - int blocking = -1; - PyObject *timeout_obj = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&O|ii$pO:channel_send_buffer", kwlist, - channel_id_converter, &cid_data, &obj, - &unboundarg, &fallbackarg, - &blocking, &timeout_obj)) - { - return NULL; - } - int64_t cid = cid_data.cid; PY_TIMEOUT_T timeout; if (PyThread_ParseTimeoutArg(timeout_obj, blocking, &timeout) < 0) { return NULL; @@ -3204,7 +3223,7 @@ channelsmod_send_buffer(PyObject *self, PyObject *args, PyObject *kwds) struct _channeldefaults defaults = {-1, -1}; if (unboundarg < 0 || fallbackarg < 0) { int err = channel_get_defaults(&_globals.channels, cid, &defaults); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } } @@ -3233,43 +3252,40 @@ channelsmod_send_buffer(PyObject *self, PyObject *args, PyObject *kwds) &_globals.channels, cid, tempobj, NULL, unboundop, fallback); } Py_DECREF(tempobj); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(channelsmod_send_buffer_doc, -"channel_send_buffer(cid, obj, *, blocking=True, timeout=None)\n\ -\n\ -Add the object's buffer to the channel's queue.\n\ -By default this waits for the object to be received."); +/*[clinic input] +_interpchannels.recv + cid: channel_id_arg + default: object = NULL + +Return a new object pair from the front of the channel's queue. + +If there is nothing to receive then raise ChannelEmptyError, unless +a default value is provided, in which case it is returned. + +Each object pair consists of (received object, None) or (None, unbound op). +[clinic start generated code]*/ static PyObject * -channelsmod_recv(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_recv_impl(PyObject *module, int64_t cid, + PyObject *default_value) +/*[clinic end generated code: output=2d3e0234570fe29a input=8b64249faa60273e]*/ { - static char *kwlist[] = {"cid", "default", NULL}; - int64_t cid; - struct channel_id_converter_data cid_data = { - .module = self, - }; - PyObject *dflt = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O:channel_recv", kwlist, - channel_id_converter, &cid_data, &dflt)) { - return NULL; - } - cid = cid_data.cid; - PyObject *obj = NULL; unboundop_t unboundop = 0; int err = channel_recv(&_globals.channels, cid, &obj, &unboundop); - if (err == ERR_CHANNEL_EMPTY && dflt != NULL) { + if (err == ERR_CHANNEL_EMPTY && default_value != NULL) { // Use the default. - obj = Py_NewRef(dflt); + obj = Py_NewRef(default_value); err = 0; } - else if (handle_channel_error(err, self, cid)) { + else if (handle_channel_error(err, module, cid)) { return NULL; } else if (obj == NULL) { @@ -3282,86 +3298,75 @@ channelsmod_recv(PyObject *self, PyObject *args, PyObject *kwds) return res; } -PyDoc_STRVAR(channelsmod_recv_doc, -"channel_recv(cid, [default]) -> (obj, unboundop)\n\ -\n\ -Return a new object from the data at the front of the channel's queue.\n\ -\n\ -If there is nothing to receive then raise ChannelEmptyError, unless\n\ -a default value is provided. In that case return it."); +/*[clinic input] +_interpchannels.close + cid: channel_id_arg + * + send: bool = False + recv: bool = False + force: bool = False + +(cid, *, send=None, recv=None, force=False) + +Close the channel for all interpreters. + +If the channel is empty then the keyword args are ignored and both +ends are immediately closed. Otherwise, if 'force' is True then +all queued items are released and both ends are immediately +closed. + +If the channel is not empty *and* 'force' is False then following +happens: + + * recv is True (regardless of send): + - raise ChannelNotEmptyError + * recv is None and send is None: + - raise ChannelNotEmptyError + * send is True and recv is not True: + - fully close the 'send' end + - close the 'recv' end to interpreters not already receiving + - fully close it once empty + +Closing an already closed channel results in a ChannelClosedError. + +Once the channel's ID has no more ref counts in any interpreter, +the channel will be destroyed. +[clinic start generated code]*/ static PyObject * -channelsmod_close(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_close_impl(PyObject *module, int64_t cid, int send, int recv, + int force) +/*[clinic end generated code: output=2b36729ca7155614 input=07f5283cc943d51e]*/ { - static char *kwlist[] = {"cid", "send", "recv", "force", NULL}; - int64_t cid; - struct channel_id_converter_data cid_data = { - .module = self, - }; - int send = 0; - int recv = 0; - int force = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&|$ppp:channel_close", kwlist, - channel_id_converter, &cid_data, - &send, &recv, &force)) { - return NULL; - } - cid = cid_data.cid; - int err = channel_close(&_globals.channels, cid, send-recv, force); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(channelsmod_close_doc, -"channel_close(cid, *, send=None, recv=None, force=False)\n\ -\n\ -Close the channel for all interpreters.\n\ -\n\ -If the channel is empty then the keyword args are ignored and both\n\ -ends are immediately closed. Otherwise, if 'force' is True then\n\ -all queued items are released and both ends are immediately\n\ -closed.\n\ -\n\ -If the channel is not empty *and* 'force' is False then following\n\ -happens:\n\ -\n\ - * recv is True (regardless of send):\n\ - - raise ChannelNotEmptyError\n\ - * recv is None and send is None:\n\ - - raise ChannelNotEmptyError\n\ - * send is True and recv is not True:\n\ - - fully close the 'send' end\n\ - - close the 'recv' end to interpreters not already receiving\n\ - - fully close it once empty\n\ -\n\ -Closing an already closed channel results in a ChannelClosedError.\n\ -\n\ -Once the channel's ID has no more ref counts in any interpreter\n\ -the channel will be destroyed."); +/*[clinic input] +_interpchannels.release + cid: channel_id_arg + * + send: bool = False + recv: bool = False + force: bool = False + +Close the channel for the current interpreter. + +The Boolean 'send' and 'recv' parameters may be used to indicate the +ends to close. By default, both ends are closed. Closing an already +closed end is a noop. +[clinic start generated code]*/ static PyObject * -channelsmod_release(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_release_impl(PyObject *module, int64_t cid, int send, + int recv, int force) +/*[clinic end generated code: output=867c031d85007973 input=5e043832dd2d5973]*/ { // Note that only the current interpreter is affected. - static char *kwlist[] = {"cid", "send", "recv", "force", NULL}; - int64_t cid; - struct channel_id_converter_data cid_data = { - .module = self, - }; - int send = 0; - int recv = 0; - int force = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&|$ppp:channel_release", kwlist, - channel_id_converter, &cid_data, - &send, &recv, &force)) { - return NULL; - } - cid = cid_data.cid; + if (send == 0 && recv == 0) { send = 1; recv = 1; @@ -3371,91 +3376,65 @@ channelsmod_release(PyObject *self, PyObject *args, PyObject *kwds) // XXX Fix implicit release. int err = channel_release(&_globals.channels, cid, send, recv); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(channelsmod_release_doc, -"channel_release(cid, *, send=None, recv=None, force=True)\n\ -\n\ -Close the channel for the current interpreter. 'send' and 'recv'\n\ -(bool) may be used to indicate the ends to close. By default both\n\ -ends are closed. Closing an already closed end is a noop."); +/*[clinic input] +_interpchannels.get_count + cid: channel_id_arg + +Return the number of items in the channel. +[clinic start generated code]*/ static PyObject * -channelsmod_get_count(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_get_count_impl(PyObject *module, int64_t cid) +/*[clinic end generated code: output=34fd5f7fc7ee3100 input=bdb9433d617dffae]*/ { - static char *kwlist[] = {"cid", NULL}; - struct channel_id_converter_data cid_data = { - .module = self, - }; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&:get_count", kwlist, - channel_id_converter, &cid_data)) { - return NULL; - } - int64_t cid = cid_data.cid; - Py_ssize_t count = -1; int err = _channel_get_count(&_globals.channels, cid, &count); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } assert(count >= 0); return PyLong_FromSsize_t(count); } -PyDoc_STRVAR(channelsmod_get_count_doc, -"get_count(cid)\n\ -\n\ -Return the number of items in the channel."); +/*[clinic input] +_interpchannels.get_info + cid: channel_id_arg + +Return details about the channel. +[clinic start generated code]*/ static PyObject * -channelsmod_get_info(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_get_info_impl(PyObject *module, int64_t cid) +/*[clinic end generated code: output=a8240bf1a49a90f7 input=ed3b2ece344aba41]*/ { - static char *kwlist[] = {"cid", NULL}; - struct channel_id_converter_data cid_data = { - .module = self, - }; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&:_get_info", kwlist, - channel_id_converter, &cid_data)) { - return NULL; - } - int64_t cid = cid_data.cid; - struct channel_info info; int err = _channel_get_info(&_globals.channels, cid, &info); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } - return new_channel_info(self, &info); + return new_channel_info(module, &info); } -PyDoc_STRVAR(channelsmod_get_info_doc, -"get_info(cid)\n\ -\n\ -Return details about the channel."); +/*[clinic input] +_interpchannels.get_channel_defaults + cid: channel_id_arg + +Return the channel's default values, set when it was created. +[clinic start generated code]*/ static PyObject * -channelsmod_get_channel_defaults(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels_get_channel_defaults_impl(PyObject *module, int64_t cid) +/*[clinic end generated code: output=a9d3424d251747b7 input=c7566d6823c9c97d]*/ { - static char *kwlist[] = {"cid", NULL}; - struct channel_id_converter_data cid_data = { - .module = self, - }; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&:get_channel_defaults", kwlist, - channel_id_converter, &cid_data)) { - return NULL; - } - int64_t cid = cid_data.cid; - struct _channeldefaults defaults = {0}; int err = channel_get_defaults(&_globals.channels, cid, &defaults); - if (handle_channel_error(err, self, cid)) { + if (handle_channel_error(err, module, cid)) { return NULL; } @@ -3463,85 +3442,63 @@ channelsmod_get_channel_defaults(PyObject *self, PyObject *args, PyObject *kwds) return res; } -PyDoc_STRVAR(channelsmod_get_channel_defaults_doc, -"get_channel_defaults(cid)\n\ -\n\ -Return the channel's default values, set when it was created."); +/*[clinic input] +_interpchannels._channel_id + *args: tuple + **kwds: dict +[clinic start generated code]*/ static PyObject * -channelsmod__channel_id(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels__channel_id_impl(PyObject *module, PyObject *args, + PyObject *kwds) +/*[clinic end generated code: output=0c5e8f860b217cf8 input=2a26155a66c51e57]*/ { - module_state *state = get_module_state(self); + module_state *state = get_module_state(module); if (state == NULL) { return NULL; } PyTypeObject *cls = state->ChannelIDType; PyObject *mod = get_module_from_owned_type(cls); - assert(mod == self); + assert(mod == module); Py_DECREF(mod); - return _channelid_new(self, cls, args, kwds); + return _channelid_new(module, cls, args, kwds); } +/*[clinic input] +_interpchannels._register_end_types + send: object(subclass_of='&PyType_Type', type='PyTypeObject *') + recv: object(subclass_of='&PyType_Type', type='PyTypeObject *') +[clinic start generated code]*/ + static PyObject * -channelsmod__register_end_types(PyObject *self, PyObject *args, PyObject *kwds) +_interpchannels__register_end_types_impl(PyObject *module, + PyTypeObject *send, + PyTypeObject *recv) +/*[clinic end generated code: output=0960fb89d7ed270f input=bf16ebee1965cff6]*/ { - static char *kwlist[] = {"send", "recv", NULL}; - PyObject *send; - PyObject *recv; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "OO:_register_end_types", kwlist, - &send, &recv)) { + if (set_channelend_types(module, send, recv) < 0) { return NULL; } - if (!PyType_Check(send)) { - PyErr_SetString(PyExc_TypeError, "expected a type for 'send'"); - return NULL; - } - if (!PyType_Check(recv)) { - PyErr_SetString(PyExc_TypeError, "expected a type for 'recv'"); - return NULL; - } - PyTypeObject *cls_send = (PyTypeObject *)send; - PyTypeObject *cls_recv = (PyTypeObject *)recv; - - if (set_channelend_types(self, cls_send, cls_recv) < 0) { - return NULL; - } - Py_RETURN_NONE; } static PyMethodDef module_functions[] = { - {"create", _PyCFunction_CAST(channelsmod_create), - METH_VARARGS | METH_KEYWORDS, channelsmod_create_doc}, - {"destroy", _PyCFunction_CAST(channelsmod_destroy), - METH_VARARGS | METH_KEYWORDS, channelsmod_destroy_doc}, - {"list_all", channelsmod_list_all, - METH_NOARGS, channelsmod_list_all_doc}, - {"list_interpreters", _PyCFunction_CAST(channelsmod_list_interpreters), - METH_VARARGS | METH_KEYWORDS, channelsmod_list_interpreters_doc}, - {"send", _PyCFunction_CAST(channelsmod_send), - METH_VARARGS | METH_KEYWORDS, channelsmod_send_doc}, - {"send_buffer", _PyCFunction_CAST(channelsmod_send_buffer), - METH_VARARGS | METH_KEYWORDS, channelsmod_send_buffer_doc}, - {"recv", _PyCFunction_CAST(channelsmod_recv), - METH_VARARGS | METH_KEYWORDS, channelsmod_recv_doc}, - {"close", _PyCFunction_CAST(channelsmod_close), - METH_VARARGS | METH_KEYWORDS, channelsmod_close_doc}, - {"release", _PyCFunction_CAST(channelsmod_release), - METH_VARARGS | METH_KEYWORDS, channelsmod_release_doc}, - {"get_count", _PyCFunction_CAST(channelsmod_get_count), - METH_VARARGS | METH_KEYWORDS, channelsmod_get_count_doc}, - {"get_info", _PyCFunction_CAST(channelsmod_get_info), - METH_VARARGS | METH_KEYWORDS, channelsmod_get_info_doc}, - {"get_channel_defaults", _PyCFunction_CAST(channelsmod_get_channel_defaults), - METH_VARARGS | METH_KEYWORDS, channelsmod_get_channel_defaults_doc}, - {"_channel_id", _PyCFunction_CAST(channelsmod__channel_id), - METH_VARARGS | METH_KEYWORDS, NULL}, - {"_register_end_types", _PyCFunction_CAST(channelsmod__register_end_types), - METH_VARARGS | METH_KEYWORDS, NULL}, + _INTERPCHANNELS_CREATE_METHODDEF + _INTERPCHANNELS_DESTROY_METHODDEF + _INTERPCHANNELS_LIST_ALL_METHODDEF + _INTERPCHANNELS_LIST_INTERPRETERS_METHODDEF + _INTERPCHANNELS_SEND_METHODDEF + _INTERPCHANNELS_SEND_BUFFER_METHODDEF + _INTERPCHANNELS_RECV_METHODDEF + _INTERPCHANNELS_CLOSE_METHODDEF + _INTERPCHANNELS_RELEASE_METHODDEF + _INTERPCHANNELS_GET_COUNT_METHODDEF + _INTERPCHANNELS_GET_INFO_METHODDEF + _INTERPCHANNELS_GET_CHANNEL_DEFAULTS_METHODDEF + _INTERPCHANNELS__CHANNEL_ID_METHODDEF + _INTERPCHANNELS__REGISTER_END_TYPES_METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/clinic/_interpchannelsmodule.c.h b/Modules/clinic/_interpchannelsmodule.c.h new file mode 100644 index 00000000000000..0b10d02690e342 --- /dev/null +++ b/Modules/clinic/_interpchannelsmodule.c.h @@ -0,0 +1,1026 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + +PyDoc_STRVAR(_interpchannels_create__doc__, +"create($module, /, unboundop=-1, fallback=-1)\n" +"--\n" +"\n" +"Create a new cross-interpreter channel and return a unique generated ID."); + +#define _INTERPCHANNELS_CREATE_METHODDEF \ + {"create", _PyCFunction_CAST(_interpchannels_create), METH_FASTCALL|METH_KEYWORDS, _interpchannels_create__doc__}, + +static PyObject * +_interpchannels_create_impl(PyObject *module, int unboundarg, + int fallbackarg); + +static PyObject * +_interpchannels_create(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(unboundop), &_Py_ID(fallback), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"unboundop", "fallback", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "create", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int unboundarg = -1; + int fallbackarg = -1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + unboundarg = PyLong_AsInt(args[0]); + if (unboundarg == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + fallbackarg = PyLong_AsInt(args[1]); + if (fallbackarg == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = _interpchannels_create_impl(module, unboundarg, fallbackarg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_destroy__doc__, +"destroy($module, /, cid)\n" +"--\n" +"\n" +"Close and finalize the channel.\n" +"\n" +"Afterward attempts to use the channel will behave as though it\n" +"never existed."); + +#define _INTERPCHANNELS_DESTROY_METHODDEF \ + {"destroy", _PyCFunction_CAST(_interpchannels_destroy), METH_FASTCALL|METH_KEYWORDS, _interpchannels_destroy__doc__}, + +static PyObject * +_interpchannels_destroy_impl(PyObject *module, int64_t cid); + +static PyObject * +_interpchannels_destroy(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "destroy", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t cid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + return_value = _interpchannels_destroy_impl(module, cid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_list_all__doc__, +"list_all($module, /)\n" +"--\n" +"\n" +"Return the list of all IDs for active channels."); + +#define _INTERPCHANNELS_LIST_ALL_METHODDEF \ + {"list_all", (PyCFunction)_interpchannels_list_all, METH_NOARGS, _interpchannels_list_all__doc__}, + +static PyObject * +_interpchannels_list_all_impl(PyObject *module); + +static PyObject * +_interpchannels_list_all(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _interpchannels_list_all_impl(module); +} + +PyDoc_STRVAR(_interpchannels_list_interpreters__doc__, +"list_interpreters($module, /, cid, *, send)\n" +"--\n" +"\n" +"Return all interpreter IDs associated with an end of the channel.\n" +"\n" +"The \'send\' argument should be a boolean indicating whether to use\n" +"the send or receive end."); + +#define _INTERPCHANNELS_LIST_INTERPRETERS_METHODDEF \ + {"list_interpreters", _PyCFunction_CAST(_interpchannels_list_interpreters), METH_FASTCALL|METH_KEYWORDS, _interpchannels_list_interpreters__doc__}, + +static PyObject * +_interpchannels_list_interpreters_impl(PyObject *module, int64_t cid, + int send); + +static PyObject * +_interpchannels_list_interpreters(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), &_Py_ID(send), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", "send", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "list_interpreters", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + int64_t cid; + int send; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 1, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + send = PyObject_IsTrue(args[1]); + if (send < 0) { + goto exit; + } + return_value = _interpchannels_list_interpreters_impl(module, cid, send); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_send__doc__, +"send($module, /, cid, obj, unboundop=-1, fallback=-1, *, blocking=True,\n" +" timeout=None)\n" +"--\n" +"\n" +"Add the object\'s data to the channel\'s queue.\n" +"\n" +"By default, this waits for the object to be received."); + +#define _INTERPCHANNELS_SEND_METHODDEF \ + {"send", _PyCFunction_CAST(_interpchannels_send), METH_FASTCALL|METH_KEYWORDS, _interpchannels_send__doc__}, + +static PyObject * +_interpchannels_send_impl(PyObject *module, int64_t cid, PyObject *obj, + int unboundarg, int fallbackarg, int blocking, + PyObject *timeout_obj); + +static PyObject * +_interpchannels_send(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 6 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), &_Py_ID(obj), &_Py_ID(unboundop), &_Py_ID(fallback), &_Py_ID(blocking), &_Py_ID(timeout), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", "obj", "unboundop", "fallback", "blocking", "timeout", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "send", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[6]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; + int64_t cid; + PyObject *obj; + int unboundarg = -1; + int fallbackarg = -1; + int blocking = 1; + PyObject *timeout_obj = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + obj = args[1]; + if (!noptargs) { + goto skip_optional_pos; + } + if (args[2]) { + unboundarg = PyLong_AsInt(args[2]); + if (unboundarg == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[3]) { + fallbackarg = PyLong_AsInt(args[3]); + if (fallbackarg == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + if (args[4]) { + blocking = PyObject_IsTrue(args[4]); + if (blocking < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + timeout_obj = args[5]; +skip_optional_kwonly: + return_value = _interpchannels_send_impl(module, cid, obj, unboundarg, fallbackarg, blocking, timeout_obj); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_send_buffer__doc__, +"send_buffer($module, /, cid, obj, unboundop=-1, fallback=-1, *,\n" +" blocking=True, timeout=None)\n" +"--\n" +"\n" +"Add the object\'s buffer to the channel\'s queue.\n" +"\n" +"By default, this waits for the object to be received."); + +#define _INTERPCHANNELS_SEND_BUFFER_METHODDEF \ + {"send_buffer", _PyCFunction_CAST(_interpchannels_send_buffer), METH_FASTCALL|METH_KEYWORDS, _interpchannels_send_buffer__doc__}, + +static PyObject * +_interpchannels_send_buffer_impl(PyObject *module, int64_t cid, + PyObject *obj, int unboundarg, + int fallbackarg, int blocking, + PyObject *timeout_obj); + +static PyObject * +_interpchannels_send_buffer(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 6 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), &_Py_ID(obj), &_Py_ID(unboundop), &_Py_ID(fallback), &_Py_ID(blocking), &_Py_ID(timeout), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", "obj", "unboundop", "fallback", "blocking", "timeout", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "send_buffer", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[6]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; + int64_t cid; + PyObject *obj; + int unboundarg = -1; + int fallbackarg = -1; + int blocking = 1; + PyObject *timeout_obj = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + obj = args[1]; + if (!noptargs) { + goto skip_optional_pos; + } + if (args[2]) { + unboundarg = PyLong_AsInt(args[2]); + if (unboundarg == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[3]) { + fallbackarg = PyLong_AsInt(args[3]); + if (fallbackarg == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + if (args[4]) { + blocking = PyObject_IsTrue(args[4]); + if (blocking < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + timeout_obj = args[5]; +skip_optional_kwonly: + return_value = _interpchannels_send_buffer_impl(module, cid, obj, unboundarg, fallbackarg, blocking, timeout_obj); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_recv__doc__, +"recv($module, /, cid, default=)\n" +"--\n" +"\n" +"Return a new object pair from the front of the channel\'s queue.\n" +"\n" +"If there is nothing to receive then raise ChannelEmptyError, unless\n" +"a default value is provided, in which case it is returned.\n" +"\n" +"Each object pair consists of (received object, None) or (None, unbound op)."); + +#define _INTERPCHANNELS_RECV_METHODDEF \ + {"recv", _PyCFunction_CAST(_interpchannels_recv), METH_FASTCALL|METH_KEYWORDS, _interpchannels_recv__doc__}, + +static PyObject * +_interpchannels_recv_impl(PyObject *module, int64_t cid, + PyObject *default_value); + +static PyObject * +_interpchannels_recv(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), &_Py_ID(default), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", "default", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "recv", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + int64_t cid; + PyObject *default_value = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + default_value = args[1]; +skip_optional_pos: + return_value = _interpchannels_recv_impl(module, cid, default_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_close__doc__, +"close($module, /, cid, *, send=False, recv=False, force=False)\n" +"--\n" +"\n" +"(cid, *, send=None, recv=None, force=False)\n" +"\n" +"Close the channel for all interpreters.\n" +"\n" +"If the channel is empty then the keyword args are ignored and both\n" +"ends are immediately closed. Otherwise, if \'force\' is True then\n" +"all queued items are released and both ends are immediately\n" +"closed.\n" +"\n" +"If the channel is not empty *and* \'force\' is False then following\n" +"happens:\n" +"\n" +" * recv is True (regardless of send):\n" +" - raise ChannelNotEmptyError\n" +" * recv is None and send is None:\n" +" - raise ChannelNotEmptyError\n" +" * send is True and recv is not True:\n" +" - fully close the \'send\' end\n" +" - close the \'recv\' end to interpreters not already receiving\n" +" - fully close it once empty\n" +"\n" +"Closing an already closed channel results in a ChannelClosedError.\n" +"\n" +"Once the channel\'s ID has no more ref counts in any interpreter,\n" +"the channel will be destroyed."); + +#define _INTERPCHANNELS_CLOSE_METHODDEF \ + {"close", _PyCFunction_CAST(_interpchannels_close), METH_FASTCALL|METH_KEYWORDS, _interpchannels_close__doc__}, + +static PyObject * +_interpchannels_close_impl(PyObject *module, int64_t cid, int send, int recv, + int force); + +static PyObject * +_interpchannels_close(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), &_Py_ID(send), &_Py_ID(recv), &_Py_ID(force), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", "send", "recv", "force", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "close", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + int64_t cid; + int send = 0; + int recv = 0; + int force = 0; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + if (!noptargs) { + goto skip_optional_kwonly; + } + if (args[1]) { + send = PyObject_IsTrue(args[1]); + if (send < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (args[2]) { + recv = PyObject_IsTrue(args[2]); + if (recv < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + force = PyObject_IsTrue(args[3]); + if (force < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _interpchannels_close_impl(module, cid, send, recv, force); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_release__doc__, +"release($module, /, cid, *, send=False, recv=False, force=False)\n" +"--\n" +"\n" +"Close the channel for the current interpreter.\n" +"\n" +"The Boolean \'send\' and \'recv\' parameters may be used to indicate the\n" +"ends to close. By default, both ends are closed. Closing an already\n" +"closed end is a noop."); + +#define _INTERPCHANNELS_RELEASE_METHODDEF \ + {"release", _PyCFunction_CAST(_interpchannels_release), METH_FASTCALL|METH_KEYWORDS, _interpchannels_release__doc__}, + +static PyObject * +_interpchannels_release_impl(PyObject *module, int64_t cid, int send, + int recv, int force); + +static PyObject * +_interpchannels_release(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), &_Py_ID(send), &_Py_ID(recv), &_Py_ID(force), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", "send", "recv", "force", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "release", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + int64_t cid; + int send = 0; + int recv = 0; + int force = 0; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + if (!noptargs) { + goto skip_optional_kwonly; + } + if (args[1]) { + send = PyObject_IsTrue(args[1]); + if (send < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (args[2]) { + recv = PyObject_IsTrue(args[2]); + if (recv < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + force = PyObject_IsTrue(args[3]); + if (force < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _interpchannels_release_impl(module, cid, send, recv, force); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_get_count__doc__, +"get_count($module, /, cid)\n" +"--\n" +"\n" +"Return the number of items in the channel."); + +#define _INTERPCHANNELS_GET_COUNT_METHODDEF \ + {"get_count", _PyCFunction_CAST(_interpchannels_get_count), METH_FASTCALL|METH_KEYWORDS, _interpchannels_get_count__doc__}, + +static PyObject * +_interpchannels_get_count_impl(PyObject *module, int64_t cid); + +static PyObject * +_interpchannels_get_count(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "get_count", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t cid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + return_value = _interpchannels_get_count_impl(module, cid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_get_info__doc__, +"get_info($module, /, cid)\n" +"--\n" +"\n" +"Return details about the channel."); + +#define _INTERPCHANNELS_GET_INFO_METHODDEF \ + {"get_info", _PyCFunction_CAST(_interpchannels_get_info), METH_FASTCALL|METH_KEYWORDS, _interpchannels_get_info__doc__}, + +static PyObject * +_interpchannels_get_info_impl(PyObject *module, int64_t cid); + +static PyObject * +_interpchannels_get_info(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "get_info", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t cid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + return_value = _interpchannels_get_info_impl(module, cid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels_get_channel_defaults__doc__, +"get_channel_defaults($module, /, cid)\n" +"--\n" +"\n" +"Return the channel\'s default values, set when it was created."); + +#define _INTERPCHANNELS_GET_CHANNEL_DEFAULTS_METHODDEF \ + {"get_channel_defaults", _PyCFunction_CAST(_interpchannels_get_channel_defaults), METH_FASTCALL|METH_KEYWORDS, _interpchannels_get_channel_defaults__doc__}, + +static PyObject * +_interpchannels_get_channel_defaults_impl(PyObject *module, int64_t cid); + +static PyObject * +_interpchannels_get_channel_defaults(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(cid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"cid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "get_channel_defaults", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t cid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!channel_id_arg_converter(module, args[0], &cid)) { + goto exit; + } + return_value = _interpchannels_get_channel_defaults_impl(module, cid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpchannels__channel_id__doc__, +"_channel_id($module, /, *args, **kwds)\n" +"--\n" +"\n"); + +#define _INTERPCHANNELS__CHANNEL_ID_METHODDEF \ + {"_channel_id", _PyCFunction_CAST(_interpchannels__channel_id), METH_VARARGS|METH_KEYWORDS, _interpchannels__channel_id__doc__}, + +static PyObject * +_interpchannels__channel_id_impl(PyObject *module, PyObject *args, + PyObject *kwds); + +static PyObject * +_interpchannels__channel_id(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + PyObject *__clinic_kwds = NULL; + + __clinic_args = Py_NewRef(args); + if (kwargs == NULL) { + __clinic_kwds = PyDict_New(); + if (__clinic_kwds == NULL) { + goto exit; + } + } + else { + __clinic_kwds = Py_NewRef(kwargs); + } + return_value = _interpchannels__channel_id_impl(module, __clinic_args, __clinic_kwds); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + /* Cleanup for kwds */ + Py_XDECREF(__clinic_kwds); + + return return_value; +} + +PyDoc_STRVAR(_interpchannels__register_end_types__doc__, +"_register_end_types($module, /, send, recv)\n" +"--\n" +"\n"); + +#define _INTERPCHANNELS__REGISTER_END_TYPES_METHODDEF \ + {"_register_end_types", _PyCFunction_CAST(_interpchannels__register_end_types), METH_FASTCALL|METH_KEYWORDS, _interpchannels__register_end_types__doc__}, + +static PyObject * +_interpchannels__register_end_types_impl(PyObject *module, + PyTypeObject *send, + PyTypeObject *recv); + +static PyObject * +_interpchannels__register_end_types(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(send), &_Py_ID(recv), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"send", "recv", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_register_end_types", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyTypeObject *send; + PyTypeObject *recv; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyObject_TypeCheck(args[0], &PyType_Type)) { + _PyArg_BadArgument("_register_end_types", "argument 'send'", (&PyType_Type)->tp_name, args[0]); + goto exit; + } + send = (PyTypeObject *)args[0]; + if (!PyObject_TypeCheck(args[1], &PyType_Type)) { + _PyArg_BadArgument("_register_end_types", "argument 'recv'", (&PyType_Type)->tp_name, args[1]); + goto exit; + } + recv = (PyTypeObject *)args[1]; + return_value = _interpchannels__register_end_types_impl(module, send, recv); + +exit: + return return_value; +} +/*[clinic end generated code: output=de3f12f7a20c9748 input=a9049054013a1b77]*/