mirror of
https://github.com/python/cpython.git
synced 2025-10-26 11:14:33 +00:00
This combines and updates our freelist handling to use a consistent implementation. Objects in the freelist are linked together using the first word of memory block. If configured with freelists disabled, these operations are essentially no-ops.
118 lines
3.2 KiB
C
118 lines
3.2 KiB
C
#ifndef Py_INTERNAL_FREELIST_H
|
|
#define Py_INTERNAL_FREELIST_H
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#ifndef Py_BUILD_CORE
|
|
# error "this header requires Py_BUILD_CORE define"
|
|
#endif
|
|
|
|
#include "pycore_freelist_state.h" // struct _Py_freelists
|
|
#include "pycore_object.h" // _PyObject_IS_GC
|
|
#include "pycore_pystate.h" // _PyThreadState_GET
|
|
#include "pycore_code.h" // OBJECT_STAT_INC
|
|
|
|
static inline struct _Py_freelists *
|
|
_Py_freelists_GET(void)
|
|
{
|
|
PyThreadState *tstate = _PyThreadState_GET();
|
|
#ifdef Py_DEBUG
|
|
_Py_EnsureTstateNotNULL(tstate);
|
|
#endif
|
|
|
|
#ifdef Py_GIL_DISABLED
|
|
return &((_PyThreadStateImpl*)tstate)->freelists;
|
|
#else
|
|
return &tstate->interp->object_state.freelists;
|
|
#endif
|
|
}
|
|
|
|
#ifndef WITH_FREELISTS
|
|
#define _Py_FREELIST_FREE(NAME, op, freefunc) freefunc(op)
|
|
#define _Py_FREELIST_PUSH(NAME, op, limit) (0)
|
|
#define _Py_FREELIST_POP(TYPE, NAME) (NULL)
|
|
#define _Py_FREELIST_POP_MEM(NAME) (NULL)
|
|
#define _Py_FREELIST_SIZE(NAME) (0)
|
|
#else
|
|
// Pushes `op` to the freelist, calls `freefunc` if the freelist is full
|
|
#define _Py_FREELIST_FREE(NAME, op, freefunc) \
|
|
_PyFreeList_Free(&_Py_freelists_GET()->NAME, _PyObject_CAST(op), \
|
|
Py_ ## NAME ## _MAXFREELIST, freefunc)
|
|
// Pushes `op` to the freelist, returns 1 if successful, 0 if the freelist is full
|
|
#define _Py_FREELIST_PUSH(NAME, op, limit) \
|
|
_PyFreeList_Push(&_Py_freelists_GET()->NAME, _PyObject_CAST(op), limit)
|
|
|
|
// Pops a PyObject from the freelist, returns NULL if the freelist is empty.
|
|
#define _Py_FREELIST_POP(TYPE, NAME) \
|
|
_Py_CAST(TYPE*, _PyFreeList_Pop(&_Py_freelists_GET()->NAME))
|
|
|
|
// Pops a non-PyObject data structure from the freelist, returns NULL if the
|
|
// freelist is empty.
|
|
#define _Py_FREELIST_POP_MEM(NAME) \
|
|
_PyFreeList_PopMem(&_Py_freelists_GET()->NAME)
|
|
|
|
#define _Py_FREELIST_SIZE(NAME) (int)((_Py_freelists_GET()->NAME).size)
|
|
|
|
static inline int
|
|
_PyFreeList_Push(struct _Py_freelist *fl, void *obj, Py_ssize_t maxsize)
|
|
{
|
|
if (fl->size < maxsize && fl->size >= 0) {
|
|
*(void **)obj = fl->freelist;
|
|
fl->freelist = obj;
|
|
fl->size++;
|
|
OBJECT_STAT_INC(to_freelist);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline void
|
|
_PyFreeList_Free(struct _Py_freelist *fl, void *obj, Py_ssize_t maxsize,
|
|
freefunc dofree)
|
|
{
|
|
if (!_PyFreeList_Push(fl, obj, maxsize)) {
|
|
dofree(obj);
|
|
}
|
|
}
|
|
|
|
static inline void *
|
|
_PyFreeList_PopNoStats(struct _Py_freelist *fl)
|
|
{
|
|
void *obj = fl->freelist;
|
|
if (obj != NULL) {
|
|
assert(fl->size > 0);
|
|
fl->freelist = *(void **)obj;
|
|
fl->size--;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
static inline PyObject *
|
|
_PyFreeList_Pop(struct _Py_freelist *fl)
|
|
{
|
|
PyObject *op = _PyFreeList_PopNoStats(fl);
|
|
if (op != NULL) {
|
|
OBJECT_STAT_INC(from_freelist);
|
|
_Py_NewReference(op);
|
|
}
|
|
return op;
|
|
}
|
|
|
|
static inline void *
|
|
_PyFreeList_PopMem(struct _Py_freelist *fl)
|
|
{
|
|
void *op = _PyFreeList_PopNoStats(fl);
|
|
if (op != NULL) {
|
|
OBJECT_STAT_INC(from_freelist);
|
|
}
|
|
return op;
|
|
}
|
|
#endif
|
|
|
|
extern void _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* !Py_INTERNAL_FREELIST_H */
|