Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1511680

Browse files
committed
Close #19757: Cleanup tracemalloc, move
PyGILState_Ensure()/PyGILState_Release() calls to the raw wrappers to simplify the code. Rename also tracemalloc_log_alloc/log_free() to tracemalloc_add_trace/remove_trace().
1 parent 9a95483 commit 1511680

1 file changed

Lines changed: 129 additions & 98 deletions

File tree

Modules/_tracemalloc.c

Lines changed: 129 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ traceback_new(void)
439439
}
440440

441441
static int
442-
tracemalloc_log_alloc(void *ptr, size_t size)
442+
tracemalloc_add_trace(void *ptr, size_t size)
443443
{
444444
traceback_t *traceback;
445445
trace_t trace;
@@ -470,7 +470,7 @@ tracemalloc_log_alloc(void *ptr, size_t size)
470470
}
471471

472472
static void
473-
tracemalloc_log_free(void *ptr)
473+
tracemalloc_remove_trace(void *ptr)
474474
{
475475
trace_t trace;
476476

@@ -483,118 +483,57 @@ tracemalloc_log_free(void *ptr)
483483
}
484484

485485
static void*
486-
tracemalloc_malloc(void *ctx, size_t size, int gil_held)
486+
tracemalloc_malloc(void *ctx, size_t size)
487487
{
488488
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
489-
#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
490-
PyGILState_STATE gil_state;
491-
#endif
492489
void *ptr;
493490

494-
if (get_reentrant()) {
495-
return alloc->malloc(alloc->ctx, size);
496-
}
497-
498-
/* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc()
499-
for allocations larger than 512 bytes. PyGILState_Ensure() may call
500-
PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if
501-
reentrant are not disabled. */
502-
set_reentrant(1);
503-
#ifdef WITH_THREAD
504-
#ifdef TRACE_RAW_MALLOC
505-
if (!gil_held)
506-
gil_state = PyGILState_Ensure();
507-
#else
508-
assert(gil_held);
509-
#endif
510-
#endif
511491
ptr = alloc->malloc(alloc->ctx, size);
492+
if (ptr == NULL)
493+
return NULL;
512494

513-
if (ptr != NULL) {
514-
if (tracemalloc_log_alloc(ptr, size) < 0) {
515-
/* Memory allocation failed */
516-
alloc->free(alloc->ctx, ptr);
517-
ptr = NULL;
518-
}
495+
if (tracemalloc_add_trace(ptr, size) < 0) {
496+
/* Failed to allocate a trace for the new memory block */
497+
alloc->free(alloc->ctx, ptr);
498+
return NULL;
519499
}
520-
set_reentrant(0);
521-
522-
#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
523-
if (!gil_held)
524-
PyGILState_Release(gil_state);
525-
#endif
526-
527500
return ptr;
528501
}
529502

530503
static void*
531-
tracemalloc_realloc(void *ctx, void *ptr, size_t new_size, int gil_held)
504+
tracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
532505
{
533506
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
534-
#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
535-
PyGILState_STATE gil_state;
536-
#endif
537507
void *ptr2;
538508

539-
if (get_reentrant()) {
540-
/* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
541-
Example: PyMem_RawRealloc() is called internally by pymalloc
542-
(_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new
543-
arena (new_arena()). */
544-
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
545-
546-
if (ptr2 != NULL && ptr != NULL)
547-
tracemalloc_log_free(ptr);
548-
549-
return ptr2;
550-
}
551-
552-
/* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
553-
allocations larger than 512 bytes. PyGILState_Ensure() may call
554-
PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if
555-
reentrant are not disabled. */
556-
set_reentrant(1);
557-
#ifdef WITH_THREAD
558-
#ifdef TRACE_RAW_MALLOC
559-
if (!gil_held)
560-
gil_state = PyGILState_Ensure();
561-
#else
562-
assert(gil_held);
563-
#endif
564-
#endif
565509
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
510+
if (ptr2 == NULL)
511+
return NULL;
566512

567-
if (ptr2 != NULL) {
568-
if (ptr != NULL) {
569-
/* resize */
570-
tracemalloc_log_free(ptr);
513+
if (ptr != NULL) {
514+
/* an existing memory block has been resized */
571515

572-
if (tracemalloc_log_alloc(ptr2, new_size) < 0) {
573-
/* Memory allocation failed. The error cannot be reported to
574-
the caller, because realloc() may already have shrinked the
575-
memory block and so removed bytes.
516+
tracemalloc_remove_trace(ptr);
576517

577-
This case is very unlikely since we just released an hash
578-
entry, so we have enough free bytes to allocate the new
579-
entry. */
580-
}
581-
}
582-
else {
583-
/* new allocation */
584-
if (tracemalloc_log_alloc(ptr2, new_size) < 0) {
585-
/* Memory allocation failed */
586-
alloc->free(alloc->ctx, ptr2);
587-
ptr2 = NULL;
588-
}
518+
if (tracemalloc_add_trace(ptr2, new_size) < 0) {
519+
/* Memory allocation failed. The error cannot be reported to
520+
the caller, because realloc() may already have shrinked the
521+
memory block and so removed bytes.
522+
523+
This case is very unlikely since we just released an hash
524+
entry, so we have enough free bytes to allocate the new
525+
entry. */
589526
}
590527
}
591-
set_reentrant(0);
592-
593-
#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
594-
if (!gil_held)
595-
PyGILState_Release(gil_state);
596-
#endif
528+
else {
529+
/* new allocation */
597530

531+
if (tracemalloc_add_trace(ptr2, new_size) < 0) {
532+
/* Failed to allocate a trace for the new memory block */
533+
alloc->free(alloc->ctx, ptr2);
534+
return NULL;
535+
}
536+
}
598537
return ptr2;
599538
}
600539

@@ -610,34 +549,126 @@ tracemalloc_free(void *ctx, void *ptr)
610549
a deadlock in PyThreadState_DeleteCurrent(). */
611550

612551
alloc->free(alloc->ctx, ptr);
613-
tracemalloc_log_free(ptr);
552+
tracemalloc_remove_trace(ptr);
614553
}
615554

616555
static void*
617556
tracemalloc_malloc_gil(void *ctx, size_t size)
618557
{
619-
return tracemalloc_malloc(ctx, size, 1);
558+
void *ptr;
559+
560+
if (get_reentrant()) {
561+
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
562+
return alloc->malloc(alloc->ctx, size);
563+
}
564+
565+
/* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for
566+
allocations larger than 512 bytes, don't trace the same memory
567+
allocation twice. */
568+
set_reentrant(1);
569+
570+
ptr = tracemalloc_malloc(ctx, size);
571+
572+
set_reentrant(0);
573+
return ptr;
620574
}
621575

622576
static void*
623577
tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
624578
{
625-
return tracemalloc_realloc(ctx, ptr, new_size, 1);
579+
void *ptr2;
580+
581+
if (get_reentrant()) {
582+
/* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
583+
Example: PyMem_RawRealloc() is called internally by pymalloc
584+
(_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new
585+
arena (new_arena()). */
586+
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
587+
588+
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
589+
if (ptr2 != NULL && ptr != NULL)
590+
tracemalloc_remove_trace(ptr);
591+
return ptr2;
592+
}
593+
594+
/* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
595+
allocations larger than 512 bytes. Don't trace the same memory
596+
allocation twice. */
597+
set_reentrant(1);
598+
599+
ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
600+
601+
set_reentrant(0);
602+
return ptr2;
626603
}
627604

628605
#ifdef TRACE_RAW_MALLOC
629606
static void*
630607
tracemalloc_raw_malloc(void *ctx, size_t size)
631608
{
632-
return tracemalloc_malloc(ctx, size, 0);
609+
#ifdef WITH_THREAD
610+
PyGILState_STATE gil_state;
611+
#endif
612+
void *ptr;
613+
614+
if (get_reentrant()) {
615+
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
616+
return alloc->malloc(alloc->ctx, size);
617+
}
618+
619+
/* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
620+
indirectly which would call PyGILState_Ensure() if reentrant are not
621+
disabled. */
622+
set_reentrant(1);
623+
624+
#ifdef WITH_THREAD
625+
gil_state = PyGILState_Ensure();
626+
ptr = tracemalloc_malloc(ctx, size);
627+
PyGILState_Release(gil_state);
628+
#else
629+
ptr = tracemalloc_malloc(ctx, size);
630+
#endif
631+
632+
set_reentrant(0);
633+
return ptr;
633634
}
634635

635636
static void*
636637
tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
637638
{
638-
return tracemalloc_realloc(ctx, ptr, new_size, 0);
639-
}
639+
#ifdef WITH_THREAD
640+
PyGILState_STATE gil_state;
640641
#endif
642+
void *ptr2;
643+
644+
if (get_reentrant()) {
645+
/* Reentrant call to PyMem_RawRealloc(). */
646+
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
647+
648+
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
649+
if (ptr2 != NULL && ptr != NULL)
650+
tracemalloc_remove_trace(ptr);
651+
652+
return ptr2;
653+
}
654+
655+
/* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
656+
indirectly which would call PyGILState_Ensure() if reentrant calls are
657+
not disabled. */
658+
set_reentrant(1);
659+
660+
#ifdef WITH_THREAD
661+
gil_state = PyGILState_Ensure();
662+
ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
663+
PyGILState_Release(gil_state);
664+
#else
665+
ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
666+
#endif
667+
668+
set_reentrant(0);
669+
return ptr2;
670+
}
671+
#endif /* TRACE_RAW_MALLOC */
641672

642673
static int
643674
tracemalloc_clear_filename(_Py_hashtable_entry_t *entry, void *user_data)

0 commit comments

Comments
 (0)