Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2227561/?format=api
{ "id": 2227561, "url": "http://patchwork.ozlabs.org/api/patches/2227561/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/patch/20260423222125.29097-9-vfazio@gmail.com/", "project": { "id": 42, "url": "http://patchwork.ozlabs.org/api/projects/42/?format=api", "name": "Linux GPIO development", "link_name": "linux-gpio", "list_id": "linux-gpio.vger.kernel.org", "list_email": "linux-gpio@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260423222125.29097-9-vfazio@gmail.com>", "list_archive_url": null, "date": "2026-04-23T22:21:25", "name": "[libgpiod,v2,8/8] bindings: python: tests: migrate the gpiosim module to multi-phase init", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "f62357c786a9b4c646e7cfc01e18781fdeca08e7", "submitter": { "id": 78694, "url": "http://patchwork.ozlabs.org/api/people/78694/?format=api", "name": "Vincent Fazio", "email": "vfazio@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-gpio/patch/20260423222125.29097-9-vfazio@gmail.com/mbox/", "series": [ { "id": 501257, "url": "http://patchwork.ozlabs.org/api/series/501257/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/list/?series=501257", "date": "2026-04-23T22:21:18", "name": "bindings: python: modernize C extensions", "version": 2, "mbox": "http://patchwork.ozlabs.org/series/501257/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2227561/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2227561/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <linux-gpio+bounces-35440-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-gpio@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=neA4dhi2;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.234.253.10; helo=sea.lore.kernel.org;\n envelope-from=linux-gpio+bounces-35440-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"neA4dhi2\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.210.45", "smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com" ], "Received": [ "from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g1rDW4WlPz1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 08:22:03 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id AB398301F4AD\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 23 Apr 2026 22:21:57 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 5885537C916;\n\tThu, 23 Apr 2026 22:21:57 +0000 (UTC)", "from mail-ot1-f45.google.com (mail-ot1-f45.google.com\n [209.85.210.45])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id A8A3A36165E\n\tfor <linux-gpio@vger.kernel.org>; Thu, 23 Apr 2026 22:21:55 +0000 (UTC)", "by mail-ot1-f45.google.com with SMTP id\n 46e09a7af769-7d4be94eeacso7244902a34.2\n for <linux-gpio@vger.kernel.org>;\n Thu, 23 Apr 2026 15:21:55 -0700 (PDT)", "from Zephyrus.localdomain ([131.93.209.211])\n by smtp.gmail.com with ESMTPSA id\n 586e51a60fabf-42b930afa63sm17784598fac.5.2026.04.23.15.21.53\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Thu, 23 Apr 2026 15:21:53 -0700 (PDT)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1776982917; cv=none;\n b=kvmp9NHcvoD8iJgrOvHKuiS0u0Fi4bLCB0XS0aKwoITyvp+uRplZnihWuLo/4VWtGVoUmvsVimSwW/OtcbOhD5lmHe9ruCfr9F3cggTRGVAj847Op4G3nztBdRLYknhg6A+O478bvnNvebVMW/r82+1MEpAHcJ9RDFjXK49tjSE=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1776982917; c=relaxed/simple;\n\tbh=nDW3zQJrJEzfq2EQ1zRjT1Yq/XLcigrgez47P0cyZR0=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=UZ6PMik28zfxuP8LQgR2FCpZjLvTXy/UY5lgW9AKIVPqzA9MLeT0i6v/Nhtf5D+pKEIml6n66mvaqVuIh4/2fjM617Z+WGh4hxb5Vl7L+dK2EyeWbO3S8TSmWq3MNMak45tEzr48h5gwiHIrnGAgSYRKVMo2xkxQyUsFmp/nYrU=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=neA4dhi2; arc=none smtp.client-ip=209.85.210.45", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1776982914; x=1777587714;\n darn=vger.kernel.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=QLcmhIcwdWxUpVcuACLh1E0xbICxTuenu22WdCqYPJw=;\n b=neA4dhi2kCtvRAT8J/bwZSgumwS4FP1y28pnuyTptJ20GYss0nGnSAKt67cP2m88d5\n DeVJ42z88foZwDDQzY51zWkOn15lr+FCGdToZwz5eiri3kiwcb75ZhWTUcyjQw6yB+Eb\n JHK6bOrJV1Zu0FOHlD0GfCBujAkYoJi7TX3YvdWwZo1HmM9o2FAvw87q9fwumucZgoAM\n +SeE8NdpZuY2fweu9uSsen5z6tLknOsumwJfcAWl5raTaM1ooyfWHuWieClD7JCL+eFK\n dqV1rOSAxKVhjF9Uy4ogxDLDceSVMtsqaTYfsNkE9Z0OojX9BlCrxdGBzXGusSIhC4Qj\n 8m4g==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776982914; x=1777587714;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=QLcmhIcwdWxUpVcuACLh1E0xbICxTuenu22WdCqYPJw=;\n b=GXKOeoGG68t0jkLJQRrkGKSjJLqDPv5xmIFq4S3VvwGtHGcqzMgEBFl/ZtFcTL9BQr\n 6S1/b8QNShu/aNTfz3Irwa8uvb9OW4CPDKmsNZYE0QBSqoaSJ2pHycn9uMV+m8BDJ04e\n nNWRiGhXi/gCXQWpQ8QZWjLj1nACOR4TEdmQkiwEftdiEZasDnkEjTkGwZyN2TfhJ1BT\n NhXm1xcYYFNleB+HPmXPJsA7OswuBsKfRjdkUe0VxiOEMxnu03fVEIIsVT2ouRlsoGTx\n uvQ2SGdaDvwutkquIdOsacWzbsoS74CPZN3sp22U5nRqZXbz2Wmj8MuMFL1mZPsyDiN8\n 6TPQ==", "X-Gm-Message-State": "AOJu0Yx+L6pQQhyvX9GwFl3jW19u2aXNYvAAcV+PRa4OZFtEWlm7W6jN\n\tH5nqjoma85OxOw82+vtR73cjy3b3PQr+hn6mQc1GuWrM/YanmRAnOYGoBpRoNQ==", "X-Gm-Gg": "AeBDietFBZKtXMUR3m5GXztPpqgzddVO09C+UbxRgGZCfSl39Dv9u2psuhDLCGvmmlf\n\tMNmx7hfBhXAH0AQim9rAoFXxWNEuitrlUVjiiDGoMXRnfgAkpU4dqlX0ym62svde3wNY1fzFMjh\n\tlK051Ux+yyui45xPSP+UNjFjaZa6hVtZd+Nivm0iPS+QdA4oy02LOB9q9cFApDWpYx2inJ9BRhw\n\tWsFSrqEsCaQUKUqKGXeDCNQDTQfKdPkyl8ykm8UQofAj5LqTO3HR6YnBOjvfs8pdbMYrAlhW38q\n\tfZ6ms0TWAfNPtcmC9Q7D4+y+EAS8HotnlD4vkZoXgHtLFSya1426/dlfI9/Anks3hkBHex3xpbd\n\tCFEbeh3T4QjBMFhXt0ai8RGZmuTPNplD0JPjEuHiCnHv1GsBO1A39TR+MDQMFgJZCIkuCAOl9UD\n\td7zlwtGMi/T8si/bAAedGJRaaF/uh6GPSkd4HSJdTm0H9UUwGUeuMydKHWkqv3GDNDEB8LFh2K", "X-Received": "by 2002:a05:6820:982:b0:694:9070:8227 with SMTP id\n 006d021491bc7-6949070840dmr9705081eaf.41.1776982914378;\n Thu, 23 Apr 2026 15:21:54 -0700 (PDT)", "From": "Vincent Fazio <vfazio@gmail.com>", "To": "linux-gpio@vger.kernel.org", "Cc": "brgl@kernel.org,\n\tVincent Fazio <vfazio@gmail.com>", "Subject": "[libgpiod][PATCH v2 8/8] bindings: python: tests: migrate the gpiosim\n module to multi-phase init", "Date": "Thu, 23 Apr 2026 17:21:25 -0500", "Message-ID": "<20260423222125.29097-9-vfazio@gmail.com>", "X-Mailer": "git-send-email 2.43.0", "In-Reply-To": "<20260423222125.29097-1-vfazio@gmail.com>", "References": "<20260423222125.29097-1-vfazio@gmail.com>", "Precedence": "bulk", "X-Mailing-List": "linux-gpio@vger.kernel.org", "List-Id": "<linux-gpio.vger.kernel.org>", "List-Subscribe": "<mailto:linux-gpio+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-gpio+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit" }, "content": "Single-phase initialization has been classified as legacy within CPython\ndocumentation [0] with multi-phase being its successor [1].\n\nAs such, switch to the new methodology.\n\nSwitching requires converting `gpiosim.Chip` to be a heap-type [2] in\norder to access the module's state [3].\n\n[0]: https://docs.python.org/3/c-api/extension-modules.html#legacy-single-phase-initialization\n[1]: https://docs.python.org/3/c-api/extension-modules.html#multi-phase-initialization\n[2]: https://docs.python.org/3/c-api/typeobj.html#heap-types\n[3]: https://docs.python.org/3/howto/isolating-extensions.html#heap-types\n\nSigned-off-by: Vincent Fazio <vfazio@gmail.com>\n---\n bindings/python/tests/gpiosim/ext.c | 151 +++++++++++++++++-----------\n 1 file changed, 94 insertions(+), 57 deletions(-)", "diff": "diff --git a/bindings/python/tests/gpiosim/ext.c b/bindings/python/tests/gpiosim/ext.c\nindex 1ebd5af..9954dd5 100644\n--- a/bindings/python/tests/gpiosim/ext.c\n+++ b/bindings/python/tests/gpiosim/ext.c\n@@ -45,21 +45,6 @@ struct module_state {\n \tstruct gpiosim_ctx *sim_ctx;\n };\n \n-static void free_module_state(void *mod)\n-{\n-\tstruct module_state *state = PyModule_GetState((PyObject *)mod);\n-\n-\tif (state->sim_ctx)\n-\t\tgpiosim_ctx_unref(state->sim_ctx);\n-}\n-\n-static PyModuleDef module_def = {\n-\tPyModuleDef_HEAD_INIT,\n-\t.m_name = \"gpiosim._ext\",\n-\t.m_size = sizeof(struct module_state),\n-\t.m_free = free_module_state,\n-};\n-\n typedef struct {\n \tPyObject_HEAD\n \tstruct gpiosim_dev *dev;\n@@ -71,13 +56,11 @@ static int chip_init(chip_object *self,\n \t\t PyObject *Py_UNUSED(ignored1))\n {\n \tstruct module_state *state;\n-\tPyObject *mod;\n \n-\tmod = PyState_FindModule(&module_def);\n-\tif (!mod)\n-\t\treturn -1;\n+\tstate = PyType_GetModuleState(Py_TYPE(self));\n \n-\tstate = PyModule_GetState(mod);\n+\tif (!state)\n+\t\treturn -1;\n \n \tself->dev = gpiosim_dev_new(state->sim_ctx);\n \tif (!self->dev) {\n@@ -111,12 +94,14 @@ static void chip_finalize(chip_object *self)\n static void chip_dealloc(PyObject *self)\n {\n \tint ret;\n+\tPyTypeObject *tp = Py_TYPE(self);\n \n \tret = PyObject_CallFinalizerFromDealloc(self);\n \tif (ret < 0)\n \t\treturn;\n \n \tPyObject_Free(self);\n+\tPy_DECREF(tp);\n }\n \n static PyObject *chip_dev_path(chip_object *self, void *Py_UNUSED(ignored))\n@@ -289,58 +274,110 @@ static PyMethodDef chip_methods[] = {\n \t{ }\n };\n \n-static PyTypeObject chip_type = {\n-\tPyVarObject_HEAD_INIT(NULL, 0)\n-\t.tp_name = \"gpiosim.Chip\",\n-\t.tp_basicsize = sizeof(chip_object),\n-\t.tp_flags = Py_TPFLAGS_DEFAULT,\n-\t.tp_new = PyType_GenericNew,\n-\t.tp_init = (initproc)chip_init,\n-\t.tp_finalize = (destructor)chip_finalize,\n-\t.tp_dealloc = (destructor)chip_dealloc,\n-\t.tp_methods = chip_methods,\n-\t.tp_getset = chip_getset,\n+static PyType_Slot chip_type_slots[] = {\n+\t{Py_tp_new, PyType_GenericNew},\n+\t{Py_tp_init, (initproc)chip_init},\n+\t{Py_tp_finalize, (destructor)chip_finalize},\n+\t{Py_tp_dealloc, (destructor)chip_dealloc},\n+\t{Py_tp_methods, chip_methods},\n+\t{Py_tp_getset, chip_getset},\n+\t{0, 0}\n };\n \n-PyMODINIT_FUNC PyInit__ext(void)\n+/*\n+See xxlimited.c and _bz2module.c for inspiration.\n+\n+As part of transitioning to multi-phase module initialization, the\n+gpiosim.Chip type needs to become heap allocated so that it can access\n+module state.\n+\n+We disallow subclassing by not specifying Py_TPFLAGS_BASETYPE. This\n+allows the module to use PyType_GetModuleState() since it may otherwise\n+not return the proper module if a subclass is invoking the method.\n+\n+Note:\n+We do not hold PyObject references so no reference cycles should exist. As such,\n+we do not set Py_TPFLAGS_HAVE_GC nor define either tp_traverse or tp_clear.\n+\n+There is still some ongoing debate about this this use case however:\n+ https://github.com/python/cpython/issues/116946\n+\n+Note:\n+If we allow subclassing in the future, reconsider use of PyObject_Free vs using\n+the function defined in the tp_free slot.\n+\n+See also:\n+ https://github.com/python/cpython/pull/138329#issuecomment-3242079564\n+ https://github.com/python/cpython/issues/116946#issuecomment-3242135537\n+ https://github.com/python/cpython/pull/139073\n+ https://github.com/python/cpython/commit/ec689187957cc80af56b9a63251bbc295bafd781\n+*/\n+static PyType_Spec chip_type_spec = {\n+\t.name = \"gpiosim.Chip\",\n+\t.basicsize = sizeof(chip_object),\n+\t.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),\n+\t.slots = chip_type_slots,\n+};\n+\n+static int module_exec(PyObject *module)\n {\n \tconst struct module_const *modconst;\n \tstruct module_state *state;\n-\tPyObject *module;\n+\tPyObject *chip_type_obj;\n \tint ret;\n \n-\tmodule = PyModule_Create(&module_def);\n-\tif (!module)\n-\t\treturn NULL;\n-\n-\tret = PyState_AddModule(module, &module_def);\n-\tif (ret) {\n-\t\tPy_DECREF(module);\n-\t\treturn NULL;\n-\t}\n-\n \tstate = PyModule_GetState(module);\n \n \tstate->sim_ctx = gpiosim_ctx_new();\n \tif (!state->sim_ctx) {\n-\t\tPy_DECREF(module);\n-\t\treturn PyErr_SetFromErrno(PyExc_OSError);\n+\t\tPyErr_SetFromErrno(PyExc_OSError);\n+\t\treturn -1;\n \t}\n \n-\tret = PyModule_AddType(module, &chip_type);\n-\tif (ret) {\n-\t\tPy_DECREF(module);\n-\t\treturn NULL;\n-\t}\n+\tchip_type_obj = PyType_FromModuleAndSpec(module, &chip_type_spec, NULL);\n+\n+\tif (!chip_type_obj)\n+\t\treturn -1;\n+\n+\tret = PyModule_AddType(module, (PyTypeObject*)chip_type_obj);\n+\tPy_DECREF(chip_type_obj);\n+\tif (ret < 0)\n+\t\treturn -1;\n \n \tfor (modconst = module_constants; modconst->name; modconst++) {\n-\t\tret = PyModule_AddIntConstant(module,\n-\t\t\t\t\t modconst->name, modconst->val);\n-\t\tif (ret) {\n-\t\t\tPy_DECREF(module);\n-\t\t\treturn NULL;\n-\t\t}\n+\t\tret = PyModule_AddIntConstant(module, modconst->name,\n+\t\t\t\t\t modconst->val);\n+\t\tif (ret < 0)\n+\t\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void free_module_state(void *mod)\n+{\n+\tstruct module_state *state = PyModule_GetState((PyObject *)mod);\n+\n+\tif (state->sim_ctx) {\n+\t\tgpiosim_ctx_unref(state->sim_ctx);\n+\t\tstate->sim_ctx = NULL;\n \t}\n+}\n+\n+static struct PyModuleDef_Slot module_slots[] = {\n+\t{Py_mod_exec, module_exec},\n+\t{0, NULL},\n+};\n+\n+static PyModuleDef module_def = {\n+\tPyModuleDef_HEAD_INIT,\n+\t.m_name = \"gpiosim._ext\",\n+\t.m_size = sizeof(struct module_state),\n+\t.m_free = free_module_state,\n+\t.m_slots = module_slots,\n+};\n \n-\treturn module;\n+PyMODINIT_FUNC PyInit__ext(void)\n+{\n+\treturn PyModuleDef_Init(&module_def);\n }\n", "prefixes": [ "libgpiod", "v2", "8/8" ] }