Skip to content

Commit 9df4d7d

Browse files
committed
pythongh-126910: Serialize perf jitdump initialization
1 parent 27da8e5 commit 9df4d7d

1 file changed

Lines changed: 19 additions & 26 deletions

File tree

Python/perf_jit_trampoline.c

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ _Static_assert(sizeof(EhFrameHeader) == 20, "EhFrameHeader layout mismatch");
280280
*/
281281
typedef struct {
282282
FILE* perf_map; // File handle for the jitdump file
283-
PyThread_type_lock map_lock; // Thread synchronization lock
283+
PyMutex map_lock; // Thread synchronization lock
284284
void* mapped_buffer; // Memory-mapped region (signals perf we're active)
285285
size_t mapped_size; // Size of the mapped region
286286
uint32_t code_id; // Counter for unique code region identifiers
@@ -413,6 +413,12 @@ static void perf_map_jit_write_header(int pid, FILE* out_file) {
413413
* Returns: Pointer to initialized state, or NULL on failure
414414
*/
415415
static void* perf_map_jit_init(void) {
416+
PyMutex_Lock(&perf_jit_map_state.map_lock);
417+
if (perf_jit_map_state.perf_map != NULL) {
418+
PyMutex_Unlock(&perf_jit_map_state.map_lock);
419+
return &perf_jit_map_state;
420+
}
421+
416422
char filename[100];
417423
int pid = getpid();
418424

@@ -422,13 +428,15 @@ static void* perf_map_jit_init(void) {
422428
/* Create/open the jitdump file with appropriate permissions */
423429
const int fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0666);
424430
if (fd == -1) {
431+
PyMutex_Unlock(&perf_jit_map_state.map_lock);
425432
return NULL; // Failed to create file
426433
}
427434

428435
/* Get system page size for memory mapping */
429436
const long page_size = sysconf(_SC_PAGESIZE);
430437
if (page_size == -1) {
431438
close(fd);
439+
PyMutex_Unlock(&perf_jit_map_state.map_lock);
432440
return NULL; // Failed to get page size
433441
}
434442

@@ -457,6 +465,7 @@ static void* perf_map_jit_init(void) {
457465
if (perf_jit_map_state.mapped_buffer == MAP_FAILED) {
458466
perf_jit_map_state.mapped_buffer = NULL;
459467
close(fd);
468+
PyMutex_Unlock(&perf_jit_map_state.map_lock);
460469
return NULL; // Memory mapping failed
461470
}
462471
(void)_PyAnnotateMemoryMap(perf_jit_map_state.mapped_buffer, page_size,
@@ -469,6 +478,7 @@ static void* perf_map_jit_init(void) {
469478
perf_jit_map_state.perf_map = fdopen(fd, "w+");
470479
if (perf_jit_map_state.perf_map == NULL) {
471480
close(fd);
481+
PyMutex_Unlock(&perf_jit_map_state.map_lock);
472482
return NULL; // Failed to create FILE*
473483
}
474484

@@ -484,19 +494,6 @@ static void* perf_map_jit_init(void) {
484494
/* Write the jitdump file header */
485495
perf_map_jit_write_header(pid, perf_jit_map_state.perf_map);
486496

487-
/*
488-
* Initialize thread synchronization lock
489-
*
490-
* Multiple threads may attempt to write to the jitdump file
491-
* simultaneously. This lock ensures thread-safe access to the
492-
* global jitdump state.
493-
*/
494-
perf_jit_map_state.map_lock = PyThread_allocate_lock();
495-
if (perf_jit_map_state.map_lock == NULL) {
496-
fclose(perf_jit_map_state.perf_map);
497-
return NULL; // Failed to create lock
498-
}
499-
500497
/* Initialize code ID counter */
501498
perf_jit_map_state.code_id = 0;
502499
perf_jit_map_state.build_id_salt =
@@ -508,6 +505,7 @@ static void* perf_map_jit_init(void) {
508505
trampoline_api.code_padding = _Py_SIZE_ROUND_UP(unwind_data_size, 16);
509506
trampoline_api.code_alignment = 32;
510507

508+
PyMutex_Unlock(&perf_jit_map_state.map_lock);
511509
return &perf_jit_map_state;
512510
}
513511

@@ -531,11 +529,9 @@ static void perf_map_jit_write_entry_with_name(
531529
)
532530
{
533531
/* Initialize jitdump system on first use */
534-
if (perf_jit_map_state.perf_map == NULL) {
535-
void* ret = perf_map_jit_init();
536-
if(ret == NULL){
537-
return; // Initialization failed, silently abort
538-
}
532+
void* ret = perf_map_jit_init();
533+
if (ret == NULL) {
534+
return; // Initialization failed, silently abort
539535
}
540536

541537
if (entry == NULL) {
@@ -583,7 +579,7 @@ static void perf_map_jit_write_entry_with_name(
583579
* a process-global code_id. Serialize the whole sequence so concurrent JIT
584580
* compilation cannot interleave records or reuse an ID.
585581
*/
586-
PyThread_acquire_lock(perf_jit_map_state.map_lock, 1);
582+
PyMutex_Lock(&perf_jit_map_state.map_lock);
587583

588584
/*
589585
* Write Code Unwinding Information Event
@@ -699,7 +695,7 @@ static void perf_map_jit_write_entry_with_name(
699695
}
700696

701697
/* Clean up allocated memory */
702-
PyThread_release_lock(perf_jit_map_state.map_lock);
698+
PyMutex_Unlock(&perf_jit_map_state.map_lock);
703699
PyMem_RawFree(perf_map_entry);
704700
}
705701

@@ -778,15 +774,12 @@ static int perf_map_jit_fini(void* state) {
778774
* writing to the file when we close it. This prevents corruption
779775
* and ensures all data is properly flushed.
780776
*/
777+
PyMutex_Lock(&perf_jit_map_state.map_lock);
781778
if (perf_jit_map_state.perf_map != NULL) {
782-
PyThread_acquire_lock(perf_jit_map_state.map_lock, 1);
783779
fclose(perf_jit_map_state.perf_map); // This also flushes buffers
784-
PyThread_release_lock(perf_jit_map_state.map_lock);
785-
786-
/* Clean up synchronization primitive */
787-
PyThread_free_lock(perf_jit_map_state.map_lock);
788780
perf_jit_map_state.perf_map = NULL;
789781
}
782+
PyMutex_Unlock(&perf_jit_map_state.map_lock);
790783

791784
/*
792785
* Unmap the memory region

0 commit comments

Comments
 (0)