Skip to content

Commit

Permalink
Merge branch 'main' into iOS-configure-reorg
Browse files Browse the repository at this point in the history
  • Loading branch information
ned-deily committed Feb 10, 2024
2 parents d714196 + d4d5bae commit 00c8965
Show file tree
Hide file tree
Showing 55 changed files with 689 additions and 138 deletions.
5 changes: 3 additions & 2 deletions Doc/c-api/code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ bound into a function.
.. c:var:: PyTypeObject PyCode_Type
This is an instance of :c:type:`PyTypeObject` representing the Python
:class:`code` type.
:ref:`code object <code-objects>`.


.. c:function:: int PyCode_Check(PyObject *co)
Return true if *co* is a :class:`code` object. This function always succeeds.
Return true if *co* is a :ref:`code object <code-objects>`.
This function always succeeds.
.. c:function:: int PyCode_GetNumFree(PyCodeObject *co)
Expand Down
17 changes: 15 additions & 2 deletions Doc/library/enum.rst
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,19 @@ Data Types
appropriate value will be chosen for you. See :class:`auto` for the
details.

.. attribute:: Enum._name_

Name of the member.

.. attribute:: Enum._value_

Value of the member, can be set in :meth:`~object.__new__`.

.. attribute:: Enum._order_

No longer used, kept for backward compatibility.
(class attribute, removed during class creation).

.. attribute:: Enum._ignore_

``_ignore_`` is only used during creation and is removed from the
Expand Down Expand Up @@ -823,8 +836,8 @@ Supported ``_sunder_`` names
- :attr:`~Enum._ignore_` -- a list of names, either as a :class:`list` or a
:class:`str`, that will not be transformed into members, and will be removed
from the final class
- :attr:`~Enum._order_` -- used in Python 2/3 code to ensure member order is
consistent (class attribute, removed during class creation)
- :attr:`~Enum._order_` -- no longer used, kept for backward
compatibility (class attribute, removed during class creation)
- :meth:`~Enum._generate_next_value_` -- used to get an appropriate value for
an enum member; may be overridden

Expand Down
1 change: 0 additions & 1 deletion Doc/tools/.nitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ Doc/library/email.compat32-message.rst
Doc/library/email.errors.rst
Doc/library/email.parser.rst
Doc/library/email.policy.rst
Doc/library/enum.rst
Doc/library/exceptions.rst
Doc/library/faulthandler.rst
Doc/library/fcntl.rst
Expand Down
6 changes: 6 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,12 @@ Build Changes
:ref:`limited C API <limited-c-api>`.
(Contributed by Victor Stinner in :gh:`85283`.)

* ``wasm32-wasi`` is now a tier 2 platform.
(Contributed by Brett Cannon in :gh:`115192`.)

* ``wasm32-emscripten`` is no longer a supported platform.
(Contributed by Brett Cannon in :gh:`115192`.)


C API Changes
=============
Expand Down
74 changes: 74 additions & 0 deletions Include/internal/pycore_brc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#ifndef Py_INTERNAL_BRC_H
#define Py_INTERNAL_BRC_H

#include <stdint.h>
#include "pycore_llist.h" // struct llist_node
#include "pycore_lock.h" // PyMutex
#include "pycore_object_stack.h" // _PyObjectStack

#ifdef __cplusplus
extern "C" {
#endif

#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif

#ifdef Py_GIL_DISABLED

// Prime number to avoid correlations with memory addresses.
#define _Py_BRC_NUM_BUCKETS 257

// Hash table bucket
struct _brc_bucket {
// Mutex protects both the bucket and thread state queues in this bucket.
PyMutex mutex;

// Linked list of _PyThreadStateImpl objects hashed to this bucket.
struct llist_node root;
};

// Per-interpreter biased reference counting state
struct _brc_state {
// Hash table of thread states by thread-id. Thread states within a bucket
// are chained using a doubly-linked list.
struct _brc_bucket table[_Py_BRC_NUM_BUCKETS];
};

// Per-thread biased reference counting state
struct _brc_thread_state {
// Linked-list of thread states per hash bucket
struct llist_node bucket_node;

// Thread-id as determined by _PyThread_Id()
uintptr_t tid;

// Objects with refcounts to be merged (protected by bucket mutex)
_PyObjectStack objects_to_merge;

// Local stack of objects to be merged (not accessed by other threads)
_PyObjectStack local_objects_to_merge;
};

// Initialize/finalize the per-thread biased reference counting state
void _Py_brc_init_thread(PyThreadState *tstate);
void _Py_brc_remove_thread(PyThreadState *tstate);

// Initialize per-interpreter state
void _Py_brc_init_state(PyInterpreterState *interp);

void _Py_brc_after_fork(PyInterpreterState *interp);

// Enqueues an object to be merged by it's owning thread (tid). This
// steals a reference to the object.
void _Py_brc_queue_object(PyObject *ob);

// Merge the refcounts of queued objects for the current thread.
void _Py_brc_merge_refcounts(PyThreadState *tstate);

#endif /* Py_GIL_DISABLED */

#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_BRC_H */
1 change: 1 addition & 0 deletions Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ void _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame)
#define _PY_ASYNC_EXCEPTION_BIT 3
#define _PY_GC_SCHEDULED_BIT 4
#define _PY_EVAL_PLEASE_STOP_BIT 5
#define _PY_EVAL_EXPLICIT_MERGE_BIT 6

/* Reserve a few bits for future use */
#define _PY_EVAL_EVENTS_BITS 8
Expand Down
1 change: 0 additions & 1 deletion Include/internal/pycore_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ extern PyTypeObject _PyContextTokenMissing_Type;
/* runtime lifecycle */

PyStatus _PyContext_Init(PyInterpreterState *);
void _PyContext_Fini(_PyFreeListState *);


/* other API */
Expand Down
1 change: 0 additions & 1 deletion Include/internal/pycore_floatobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ extern "C" {

extern void _PyFloat_InitState(PyInterpreterState *);
extern PyStatus _PyFloat_InitTypes(PyInterpreterState *);
extern void _PyFloat_Fini(_PyFreeListState *);
extern void _PyFloat_FiniType(PyInterpreterState *);


Expand Down
10 changes: 10 additions & 0 deletions Include/internal/pycore_freelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ typedef struct _Py_freelist_state {
struct _Py_object_stack_state object_stacks;
} _PyFreeListState;

extern void _PyObject_ClearFreeLists(_PyFreeListState *state, int is_finalization);
extern void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PySlice_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyDict_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyAsyncGen_ClearFreeLists(_PyFreeListState *state, int is_finalization);
extern void _PyContext_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyObjectStackChunk_ClearFreeList(_PyFreeListState *state, int is_finalization);

#ifdef __cplusplus
}
#endif
Expand Down
8 changes: 0 additions & 8 deletions Include/internal/pycore_gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,14 +279,6 @@ extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs);

// Functions to clear types free lists
extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp);
extern void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization);
extern void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PySlice_ClearCache(_PyFreeListState *state);
extern void _PyDict_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyAsyncGen_ClearFreeLists(_PyFreeListState *state, int is_finalization);
extern void _PyContext_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _Py_ScheduleGC(PyInterpreterState *interp);
extern void _Py_RunGC(PyThreadState *tstate);

Expand Down
4 changes: 0 additions & 4 deletions Include/internal/pycore_genobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ extern PyTypeObject _PyCoroWrapper_Type;
extern PyTypeObject _PyAsyncGenWrappedValue_Type;
extern PyTypeObject _PyAsyncGenAThrow_Type;

/* runtime lifecycle */

extern void _PyAsyncGen_Fini(_PyFreeListState *);

#ifdef __cplusplus
}
#endif
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ struct _is {

#if defined(Py_GIL_DISABLED)
struct _mimalloc_interp_state mimalloc;
struct _brc_state brc; // biased reference counting state
#endif

// Per-interpreter state for the obmalloc allocator. For the main
Expand Down
6 changes: 0 additions & 6 deletions Include/internal/pycore_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ extern "C" {
extern PyObject* _PyList_Extend(PyListObject *, PyObject *);
extern void _PyList_DebugMallocStats(FILE *out);


/* runtime lifecycle */

extern void _PyList_Fini(_PyFreeListState *);


#define _PyList_ITEMS(op) _Py_RVALUE(_PyList_CAST(op)->ob_item)

extern int
Expand Down
9 changes: 6 additions & 3 deletions Include/internal/pycore_object_stack.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef Py_INTERNAL_OBJECT_STACK_H
#define Py_INTERNAL_OBJECT_STACK_H

#include "pycore_freelist.h" // _PyFreeListState

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -32,9 +34,6 @@ _PyObjectStackChunk_New(void);
extern void
_PyObjectStackChunk_Free(_PyObjectStackChunk *);

extern void
_PyObjectStackChunk_ClearFreeList(_PyFreeListState *state, int is_finalization);

// Push an item onto the stack. Return -1 on allocation failure, 0 on success.
static inline int
_PyObjectStack_Push(_PyObjectStack *stack, PyObject *obj)
Expand Down Expand Up @@ -74,6 +73,10 @@ _PyObjectStack_Pop(_PyObjectStack *stack)
return obj;
}

// Merge src into dst, leaving src empty
extern void
_PyObjectStack_Merge(_PyObjectStack *dst, _PyObjectStack *src);

// Remove all items from the stack
extern void
_PyObjectStack_Clear(_PyObjectStack *stack);
Expand Down
2 changes: 0 additions & 2 deletions Include/internal/pycore_sliceobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ extern "C" {

/* runtime lifecycle */

extern void _PySlice_Fini(_PyFreeListState *);

extern PyObject *
_PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop);

Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_tstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern "C" {

#include "pycore_freelist.h" // struct _Py_freelist_state
#include "pycore_mimalloc.h" // struct _mimalloc_thread_state
#include "pycore_brc.h" // struct _brc_thread_state


// Every PyThreadState is actually allocated as a _PyThreadStateImpl. The
Expand All @@ -22,6 +23,7 @@ typedef struct _PyThreadStateImpl {
#ifdef Py_GIL_DISABLED
struct _mimalloc_thread_state mimalloc;
struct _Py_freelist_state freelist_state;
struct _brc_thread_state brc;
#endif

} _PyThreadStateImpl;
Expand Down
1 change: 0 additions & 1 deletion Include/internal/pycore_tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ extern void _PyTuple_DebugMallocStats(FILE *out);
/* runtime lifecycle */

extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
extern void _PyTuple_Fini(_PyFreeListState *);


/* other API */
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,7 @@ def __init__(self, f, test):
self.test = test
def run(self):
del self.f
gc_collect()
self.test.assertEqual(LAST_FREED, 500)

SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(500))
Expand Down
17 changes: 15 additions & 2 deletions Lib/test/test_concurrent_futures/executor.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import threading
import time
import unittest
import weakref
from concurrent import futures
from test import support
from test.support import Py_GIL_DISABLED


def mul(x, y):
Expand Down Expand Up @@ -83,10 +85,21 @@ def test_no_stale_references(self):
my_object_collected = threading.Event()
my_object_callback = weakref.ref(
my_object, lambda obj: my_object_collected.set())
# Deliberately discarding the future.
self.executor.submit(my_object.my_method)
fut = self.executor.submit(my_object.my_method)
del my_object

if Py_GIL_DISABLED:
# Due to biased reference counting, my_object might only be
# deallocated while the thread that created it runs -- if the
# thread is paused waiting on an event, it may not merge the
# refcount of the queued object. For that reason, we wait for the
# task to finish (so that it's no longer referenced) and force a
# GC to ensure that it is collected.
fut.result() # Wait for the task to finish.
support.gc_collect()
else:
del fut # Deliberately discard the future.

collected = my_object_collected.wait(timeout=support.SHORT_TIMEOUT)
self.assertTrue(collected,
"Stale reference not collected within timeout.")
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_concurrent_futures/test_process_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def test_ressources_gced_in_workers(self):

# explicitly destroy the object to ensure that EventfulGCObj.__del__()
# is called while manager is still running.
support.gc_collect()
obj = None
support.gc_collect()

Expand Down
Loading

0 comments on commit 00c8965

Please sign in to comment.