Skip to content

Commit

Permalink
pal init: Init membarrier() before first thread to improve start time
Browse files Browse the repository at this point in the history
Refactor InitializeFlushProcessWriteBuffers(): Split membarrier()
initialization into a new InitializeMembarrier() helper function.

InitializeMembarrier() earlier before first thread is created to improve
process start time on Linux. More details can be found in issue 106722.

Fixes #106722
  • Loading branch information
Haris Okanovic committed Aug 20, 2024
1 parent 57502fc commit 10107a0
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 15 deletions.
9 changes: 9 additions & 0 deletions src/coreclr/pal/src/include/pal/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ Return
--*/
BOOL InitializeFlushProcessWriteBuffers();

/*++
Function:
InitializeMembarrier
Abstract
This function initializes the Linux "expedited membarrier" syscall, if available
--*/
void InitializeMembarrier();

#ifdef __cplusplus
}
#endif // __cplusplus
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/pal/src/init/pal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,10 @@ Initialize(
}
#endif // __APPLE__

// Init "expedited membarrier" as soon as possible (before worker
// threads are created) for faster process startup on Linux.
InitializeMembarrier();

CriticalSectionSubSysInitialize();

if(nullptr == init_critsec)
Expand Down
51 changes: 36 additions & 15 deletions src/coreclr/pal/src/thread/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,10 @@ enum membarrier_cmd
};

//
// Tracks if the OS supports FlushProcessWriteBuffers using membarrier
// Tracks if membarrier is initialized and available on the current system
//
static int s_flushUsingMemBarrier = 0;
static BOOL s_membarrierInitialized = FALSE;
static BOOL s_membarrierAvailable = FALSE;

//
// Helper memory page used by the FlushProcessWriteBuffers
Expand Down Expand Up @@ -2562,6 +2563,35 @@ PROCAbort(int signal, siginfo_t* siginfo)
abort();
}

/*++
Function:
InitializeMembarrier
Abstract
This function initializes the Linux "expedited membarrier" syscall, if available
--*/
void
InitializeMembarrier()
{
if (!s_membarrierInitialized)
{
// Starting with Linux kernel 4.14, process memory barriers can be generated
// using MEMBARRIER_CMD_PRIVATE_EXPEDITED.
int mask = membarrier(MEMBARRIER_CMD_QUERY, 0);
if (mask >= 0 &&
mask & MEMBARRIER_CMD_PRIVATE_EXPEDITED)
{
// Register intent to use the private expedited command.
if (membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0) == 0)
{
s_membarrierAvailable = TRUE;
}
}
}

s_membarrierInitialized = TRUE;
}

/*++
Function:
InitializeFlushProcessWriteBuffers
Expand All @@ -2575,20 +2605,11 @@ BOOL
InitializeFlushProcessWriteBuffers()
{
_ASSERTE(s_helperPage == 0);
_ASSERTE(s_flushUsingMemBarrier == 0);

// Starting with Linux kernel 4.14, process memory barriers can be generated
// using MEMBARRIER_CMD_PRIVATE_EXPEDITED.
int mask = membarrier(MEMBARRIER_CMD_QUERY, 0);
if (mask >= 0 &&
mask & MEMBARRIER_CMD_PRIVATE_EXPEDITED)
InitializeMembarrier();
if (s_membarrierAvailable)
{
// Register intent to use the private expedited command.
if (membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0) == 0)
{
s_flushUsingMemBarrier = TRUE;
return TRUE;
}
return TRUE;
}

#ifdef TARGET_OSX
Expand Down Expand Up @@ -2645,7 +2666,7 @@ VOID
PALAPI
FlushProcessWriteBuffers()
{
if (s_flushUsingMemBarrier)
if (s_membarrierAvailable)
{
int status = membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED, 0);
FATAL_ASSERT(status == 0, "Failed to flush using membarrier");
Expand Down

0 comments on commit 10107a0

Please sign in to comment.