mirror of
https://github.com/python/cpython.git
synced 2025-11-09 10:01:42 +00:00
Biased reference counting maintains two refcount fields in each object: `ob_ref_local` and `ob_ref_shared`. The true refcount is the sum of these two fields. In some cases, when refcounting operations are split across threads, the ob_ref_shared field can be negative (although the total refcount must be at least zero). In this case, the thread that decremented the refcount requests that the owning thread give up ownership and merge the refcount fields.
90 lines
2.2 KiB
C
90 lines
2.2 KiB
C
#ifndef Py_INTERNAL_OBJECT_STACK_H
|
|
#define Py_INTERNAL_OBJECT_STACK_H
|
|
|
|
#include "pycore_freelist.h" // _PyFreeListState
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#ifndef Py_BUILD_CORE
|
|
# error "this header requires Py_BUILD_CORE define"
|
|
#endif
|
|
|
|
// _PyObjectStack is a stack of Python objects implemented as a linked list of
|
|
// fixed size buffers.
|
|
|
|
// Chosen so that _PyObjectStackChunk is a power-of-two size.
|
|
#define _Py_OBJECT_STACK_CHUNK_SIZE 254
|
|
|
|
typedef struct _PyObjectStackChunk {
|
|
struct _PyObjectStackChunk *prev;
|
|
Py_ssize_t n;
|
|
PyObject *objs[_Py_OBJECT_STACK_CHUNK_SIZE];
|
|
} _PyObjectStackChunk;
|
|
|
|
typedef struct _PyObjectStack {
|
|
_PyObjectStackChunk *head;
|
|
} _PyObjectStack;
|
|
|
|
|
|
extern _PyObjectStackChunk *
|
|
_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)
|
|
{
|
|
_PyObjectStackChunk *buf = stack->head;
|
|
if (buf == NULL || buf->n == _Py_OBJECT_STACK_CHUNK_SIZE) {
|
|
buf = _PyObjectStackChunk_New();
|
|
if (buf == NULL) {
|
|
return -1;
|
|
}
|
|
buf->prev = stack->head;
|
|
buf->n = 0;
|
|
stack->head = buf;
|
|
}
|
|
|
|
assert(buf->n >= 0 && buf->n < _Py_OBJECT_STACK_CHUNK_SIZE);
|
|
buf->objs[buf->n] = obj;
|
|
buf->n++;
|
|
return 0;
|
|
}
|
|
|
|
// Pop the top item from the stack. Return NULL if the stack is empty.
|
|
static inline PyObject *
|
|
_PyObjectStack_Pop(_PyObjectStack *stack)
|
|
{
|
|
_PyObjectStackChunk *buf = stack->head;
|
|
if (buf == NULL) {
|
|
return NULL;
|
|
}
|
|
assert(buf->n > 0 && buf->n <= _Py_OBJECT_STACK_CHUNK_SIZE);
|
|
buf->n--;
|
|
PyObject *obj = buf->objs[buf->n];
|
|
if (buf->n == 0) {
|
|
stack->head = buf->prev;
|
|
_PyObjectStackChunk_Free(buf);
|
|
}
|
|
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);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif // !Py_INTERNAL_OBJECT_STACK_H
|