Skip to content
Closed
Prev Previous commit
Next Next commit
Merge remote-tracking branch 'origin/main' into fix-issue-42969
  • Loading branch information
jbms committed May 2, 2023
commit e71b95954abc38eca873b42fb24cdeecccef1c50
7 changes: 7 additions & 0 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ typedef struct pyruntimestate {
*/
uintptr_t finalize_blocks;

struct _pymem_allocators allocators;
struct _obmalloc_global_state obmalloc;
struct pyhash_runtime_state pyhash_state;
struct _time_runtime_state time;
struct _pythread_runtime_state threads;
struct _signals_runtime_state signals;

struct pyinterpreters {
PyThread_type_lock mutex;
/* The linked list of interpreters, newest first. */
Expand Down
51 changes: 51 additions & 0 deletions Misc/stable_abi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2346,6 +2346,57 @@

[typedef.vectorcallfunc]
added = '3.12'
[function.PyObject_Vectorcall]
added = '3.12'
[function.PyObject_VectorcallMethod]
added = '3.12'
[macro.PY_VECTORCALL_ARGUMENTS_OFFSET]
added = '3.12'
[typedef.getbufferproc]
added = '3.12'
[typedef.releasebufferproc]
added = '3.12'

[const.Py_T_BYTE]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_SHORT]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_INT]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_LONG]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_LONGLONG]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_UBYTE]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_UINT]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_USHORT]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_ULONG]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_ULONGLONG]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_PYSSIZET]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_FLOAT]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_DOUBLE]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_BOOL]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_STRING]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_STRING_INPLACE]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_CHAR]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_T_OBJECT_EX]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_READONLY]
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_AUDIT_READ]
added = '3.12' # Before 3.12, available in "structmember.h"
[function.PyGILState_ReleaseGILAndFinalizeBlock]
added = '3.12'
[function.PyGILState_TryAcquireFinalizeBlockAndGIL]
Expand Down
284 changes: 284 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3249,6 +3249,280 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args))
Py_RETURN_NONE;
}

static PyObject *
function_get_code(PyObject *self, PyObject *func)
{
PyObject *code = PyFunction_GetCode(func);
if (code != NULL) {
return Py_NewRef(code);
} else {
return NULL;
}
}

static PyObject *
function_get_globals(PyObject *self, PyObject *func)
{
PyObject *globals = PyFunction_GetGlobals(func);
if (globals != NULL) {
return Py_NewRef(globals);
} else {
return NULL;
}
}

static PyObject *
function_get_module(PyObject *self, PyObject *func)
{
PyObject *module = PyFunction_GetModule(func);
if (module != NULL) {
return Py_NewRef(module);
} else {
return NULL;
}
}

static PyObject *
function_get_defaults(PyObject *self, PyObject *func)
{
PyObject *defaults = PyFunction_GetDefaults(func);
if (defaults != NULL) {
return Py_NewRef(defaults);
} else if (PyErr_Occurred()) {
return NULL;
} else {
Py_RETURN_NONE; // This can happen when `defaults` are set to `None`
}
}

static PyObject *
function_set_defaults(PyObject *self, PyObject *args)
{
PyObject *func = NULL, *defaults = NULL;
if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) {
return NULL;
}
int result = PyFunction_SetDefaults(func, defaults);
if (result == -1)
return NULL;
Py_RETURN_NONE;
}

static PyObject *
function_get_kw_defaults(PyObject *self, PyObject *func)
{
PyObject *defaults = PyFunction_GetKwDefaults(func);
if (defaults != NULL) {
return Py_NewRef(defaults);
} else if (PyErr_Occurred()) {
return NULL;
} else {
Py_RETURN_NONE; // This can happen when `kwdefaults` are set to `None`
}
}

static PyObject *
function_set_kw_defaults(PyObject *self, PyObject *args)
{
PyObject *func = NULL, *defaults = NULL;
if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) {
return NULL;
}
int result = PyFunction_SetKwDefaults(func, defaults);
if (result == -1)
return NULL;
Py_RETURN_NONE;
}

struct gc_visit_state_basic {
PyObject *target;
int found;
};

static int
gc_visit_callback_basic(PyObject *obj, void *arg)
{
struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg;
if (obj == state->target) {
state->found = 1;
return 0;
}
return 1;
}

static PyObject *
test_gc_visit_objects_basic(PyObject *Py_UNUSED(self),
PyObject *Py_UNUSED(ignored))
{
PyObject *obj;
struct gc_visit_state_basic state;

obj = PyList_New(0);
if (obj == NULL) {
return NULL;
}
state.target = obj;
state.found = 0;

PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state);
Py_DECREF(obj);
if (!state.found) {
PyErr_SetString(
PyExc_AssertionError,
"test_gc_visit_objects_basic: Didn't find live list");
return NULL;
}
Py_RETURN_NONE;
}

static int
gc_visit_callback_exit_early(PyObject *obj, void *arg)
{
int *visited_i = (int *)arg;
(*visited_i)++;
if (*visited_i == 2) {
return 0;
}
return 1;
}

static PyObject *
test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self),
PyObject *Py_UNUSED(ignored))
{
int visited_i = 0;
PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i);
if (visited_i != 2) {
PyErr_SetString(
PyExc_AssertionError,
"test_gc_visit_objects_exit_early: did not exit when expected");
}
Py_RETURN_NONE;
}

typedef struct {
PyObject_HEAD
} ObjExtraData;

static PyObject *
obj_extra_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
size_t extra_size = sizeof(PyObject *);
PyObject *obj = PyUnstable_Object_GC_NewWithExtraData(type, extra_size);
if (obj == NULL) {
return PyErr_NoMemory();
}
PyObject_GC_Track(obj);
return obj;
}

static PyObject **
obj_extra_data_get_extra_storage(PyObject *self)
{
return (PyObject **)((char *)self + Py_TYPE(self)->tp_basicsize);
}

static PyObject *
obj_extra_data_get(PyObject *self, void *Py_UNUSED(ignored))
{
PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
PyObject *value = *extra_storage;
if (!value) {
Py_RETURN_NONE;
}
return Py_NewRef(value);
}

static int
obj_extra_data_set(PyObject *self, PyObject *newval, void *Py_UNUSED(ignored))
{
PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
Py_CLEAR(*extra_storage);
if (newval) {
*extra_storage = Py_NewRef(newval);
}
return 0;
}

static PyGetSetDef obj_extra_data_getset[] = {
{"extra", (getter)obj_extra_data_get, (setter)obj_extra_data_set, NULL},
{NULL}
};

static int
obj_extra_data_traverse(PyObject *self, visitproc visit, void *arg)
{
PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
PyObject *value = *extra_storage;
Py_VISIT(value);
return 0;
}

static int
obj_extra_data_clear(PyObject *self)
{
PyObject **extra_storage = obj_extra_data_get_extra_storage(self);
Py_CLEAR(*extra_storage);
return 0;
}

static void
obj_extra_data_dealloc(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
obj_extra_data_clear(self);
tp->tp_free(self);
Py_DECREF(tp);
}

static PyType_Slot ObjExtraData_Slots[] = {
{Py_tp_getset, obj_extra_data_getset},
{Py_tp_dealloc, obj_extra_data_dealloc},
{Py_tp_traverse, obj_extra_data_traverse},
{Py_tp_clear, obj_extra_data_clear},
{Py_tp_new, obj_extra_data_new},
{Py_tp_free, PyObject_GC_Del},
{0, NULL},
};

static PyType_Spec ObjExtraData_TypeSpec = {
.name = "_testcapi.ObjExtraData",
.basicsize = sizeof(ObjExtraData),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.slots = ObjExtraData_Slots,
};

struct atexit_data {
int called;
};

static void
callback(void *data)
{
((struct atexit_data *)data)->called += 1;
}

static PyObject *
test_atexit(PyObject *self, PyObject *Py_UNUSED(args))
{
PyThreadState *oldts = PyThreadState_Swap(NULL);
PyThreadState *tstate = Py_NewInterpreter();

struct atexit_data data = {0};
int res = _Py_AtExit(tstate->interp, callback, (void *)&data);
Py_EndInterpreter(tstate);
PyThreadState_Swap(oldts);
if (res < 0) {
return NULL;
}
if (data.called == 0) {
PyErr_SetString(PyExc_RuntimeError, "atexit callback not called");
return NULL;
}
Py_RETURN_NONE;
}

// Used by `finalize_thread_hang`.
#ifdef _POSIX_THREADS
static void finalize_thread_hang_cleanup_callback(void *Py_UNUSED(arg)) {
Expand Down Expand Up @@ -3426,6 +3700,16 @@ static PyMethodDef TestMethods[] = {
{"settrace_to_record", settrace_to_record, METH_O, NULL},
{"test_macros", test_macros, METH_NOARGS, NULL},
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
{"function_get_code", function_get_code, METH_O, NULL},
{"function_get_globals", function_get_globals, METH_O, NULL},
{"function_get_module", function_get_module, METH_O, NULL},
{"function_get_defaults", function_get_defaults, METH_O, NULL},
{"function_set_defaults", function_set_defaults, METH_VARARGS, NULL},
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
{"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL},
{"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL},
{"test_atexit", test_atexit, METH_NOARGS},
{"finalize_thread_hang", finalize_thread_hang, METH_O, NULL},
{"acquire_finalize_block", acquire_finalize_block, METH_NOARGS, NULL},
{"release_finalize_block", release_finalize_block, METH_NOARGS, NULL},
Expand Down
1 change: 0 additions & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "Python.h"

#include "condvar.h"
#include "pycore_bytesobject.h" // _PyBytes_InitTypes()
#include "pycore_ceval.h" // _PyEval_FiniGIL()
#include "pycore_context.h" // _PyContext_Init()
#include "pycore_exceptions.h" // _PyExc_InitTypes()
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.