1
0
mirror of https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git synced 2026-10-24 00:48:53 +03:00
Files
libgpiod/bindings/python/gpiod/ext/module.c
Vincent Fazio c9378d6c63 bindings: python: support free-threaded CPython
PEP 703 [0] discusses making the GIL optional in certain builds of the
CPython interpreter.

This build option was available experiementally in Python 3.13 but has
since been stabilized in Python 3.14 per PEP 779 [1].

According to the porting guide [2], there is no strict requirement that
C extensions must be thread-safe.

Experiments have shown that no logic changes are required if callers
use sychronization mechanisms provided by the Python standard library.

The documentation has been updated to call this out specifically using
terminology from the porting guide [3].

[0]: https://peps.python.org/pep-0703/
[1]: https://peps.python.org/pep-0779/
[2]: https://py-free-threading.github.io/porting/#define-and-document-thread-safety-guarantees
[3]: https://py-free-threading.github.io/documentation-principles/#free-threading-terminology

Signed-off-by: Vincent Fazio <vfazio@gmail.com>
Link: https://patch.msgid.link/20260527215922.18678-3-vfazio@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-05-28 10:59:30 +02:00

208 lines
3.8 KiB
C

// SPDX-License-Identifier: LGPL-2.1-or-later
// SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
#include <gpiod.h>
#include <Python.h>
struct module_const {
const char *name;
long val;
};
static const struct module_const module_constants[] = {
{
.name = "VALUE_INACTIVE",
.val = GPIOD_LINE_VALUE_INACTIVE,
},
{
.name = "VALUE_ACTIVE",
.val = GPIOD_LINE_VALUE_ACTIVE,
},
{
.name = "DIRECTION_AS_IS",
.val = GPIOD_LINE_DIRECTION_AS_IS,
},
{
.name = "DIRECTION_INPUT",
.val = GPIOD_LINE_DIRECTION_INPUT,
},
{
.name = "DIRECTION_OUTPUT",
.val = GPIOD_LINE_DIRECTION_OUTPUT,
},
{
.name = "BIAS_AS_IS",
.val = GPIOD_LINE_BIAS_AS_IS,
},
{
.name = "BIAS_UNKNOWN",
.val = GPIOD_LINE_BIAS_UNKNOWN,
},
{
.name = "BIAS_DISABLED",
.val = GPIOD_LINE_BIAS_DISABLED,
},
{
.name = "BIAS_PULL_UP",
.val = GPIOD_LINE_BIAS_PULL_UP,
},
{
.name = "BIAS_PULL_DOWN",
.val = GPIOD_LINE_BIAS_PULL_DOWN,
},
{
.name = "DRIVE_PUSH_PULL",
.val = GPIOD_LINE_DRIVE_PUSH_PULL,
},
{
.name = "DRIVE_OPEN_DRAIN",
.val = GPIOD_LINE_DRIVE_OPEN_DRAIN,
},
{
.name = "DRIVE_OPEN_SOURCE",
.val = GPIOD_LINE_DRIVE_OPEN_SOURCE,
},
{
.name = "EDGE_NONE",
.val = GPIOD_LINE_EDGE_NONE,
},
{
.name = "EDGE_FALLING",
.val = GPIOD_LINE_EDGE_FALLING,
},
{
.name = "EDGE_RISING",
.val = GPIOD_LINE_EDGE_RISING,
},
{
.name = "EDGE_BOTH",
.val = GPIOD_LINE_EDGE_BOTH,
},
{
.name = "CLOCK_MONOTONIC",
.val = GPIOD_LINE_CLOCK_MONOTONIC,
},
{
.name = "CLOCK_REALTIME",
.val = GPIOD_LINE_CLOCK_REALTIME,
},
{
.name = "CLOCK_HTE",
.val = GPIOD_LINE_CLOCK_HTE,
},
{
.name = "EDGE_EVENT_TYPE_RISING",
.val = GPIOD_EDGE_EVENT_RISING_EDGE,
},
{
.name = "EDGE_EVENT_TYPE_FALLING",
.val = GPIOD_EDGE_EVENT_FALLING_EDGE,
},
{
.name = "INFO_EVENT_TYPE_LINE_REQUESTED",
.val = GPIOD_INFO_EVENT_LINE_REQUESTED,
},
{
.name = "INFO_EVENT_TYPE_LINE_RELEASED",
.val = GPIOD_INFO_EVENT_LINE_RELEASED,
},
{
.name = "INFO_EVENT_TYPE_LINE_CONFIG_CHANGED",
.val = GPIOD_INFO_EVENT_LINE_CONFIG_CHANGED,
},
{ }
};
static PyObject *
module_is_gpiochip_device(PyObject *Py_UNUSED(self), PyObject *args)
{
const char *path;
int ret;
ret = PyArg_ParseTuple(args, "s", &path);
if (!ret)
return NULL;
return PyBool_FromLong(gpiod_is_gpiochip_device(path));
}
static PyMethodDef module_methods[] = {
{
.ml_name = "is_gpiochip_device",
.ml_meth = (PyCFunction)module_is_gpiochip_device,
.ml_flags = METH_VARARGS,
},
{ }
};
extern PyTypeObject chip_type;
extern PyTypeObject line_config_type;
extern PyTypeObject line_settings_type;
extern PyTypeObject request_type;
static PyTypeObject *types[] = {
&chip_type,
&line_config_type,
&line_settings_type,
&request_type,
NULL,
};
static int module_exec(PyObject* module)
{
const struct module_const *modconst;
PyObject *all;
PyTypeObject **type;
int ret;
ret = PyModule_AddStringConstant(module, "api_version",
gpiod_api_version());
if (ret < 0)
return -1;
all = PyList_New(0);
if (!all)
return -1;
ret = PyModule_AddObjectRef(module, "__all__", all);
Py_DECREF(all);
if (ret)
return -1;
for (type = types; *type; type++) {
ret = PyModule_AddType(module, *type);
if (ret < 0)
return -1;
}
for (modconst = module_constants; modconst->name; modconst++) {
ret = PyModule_AddIntConstant(module, modconst->name,
modconst->val);
if (ret < 0)
return -1;
}
return 0;
}
static struct PyModuleDef_Slot module_slots[] = {
{ Py_mod_exec, module_exec },
#if PY_VERSION_HEX >= 0x030E0000 && defined(Py_GIL_DISABLED)
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
#endif
{0, NULL},
};
static PyModuleDef module_def = {
PyModuleDef_HEAD_INIT,
.m_name = "gpiod._ext",
.m_methods = module_methods,
.m_slots = module_slots,
};
PyMODINIT_FUNC PyInit__ext(void)
{
return PyModuleDef_Init(&module_def);
}