diff options
author | Jan Vorlicek <janvorli@microsoft.com> | 2015-05-27 22:39:55 +0200 |
---|---|---|
committer | Jan Vorlicek <janvorli@microsoft.com> | 2015-05-27 22:39:55 +0200 |
commit | 00b1f12e47390f6c013f6d0320e636fcf07dd754 (patch) | |
tree | a558c6f772c78e11f10dcd5dda4b97435cbeba72 /src | |
parent | fd25910833452ce8afbc8f09d3147278d96273c8 (diff) | |
parent | e79b9ed5cde41c65e37ff4cc8b8a084f1511f9eb (diff) | |
download | coreclr-00b1f12e47390f6c013f6d0320e636fcf07dd754.tar.gz coreclr-00b1f12e47390f6c013f6d0320e636fcf07dd754.tar.bz2 coreclr-00b1f12e47390f6c013f6d0320e636fcf07dd754.zip |
Merge pull request #1057 from janvorli/flush-process-write-buffers-page
Implement FlushProcessWriteBuffers using the page protection mechanism
Diffstat (limited to 'src')
-rw-r--r-- | src/pal/src/include/pal/process.h | 11 | ||||
-rw-r--r-- | src/pal/src/init/pal.cpp | 5 | ||||
-rw-r--r-- | src/pal/src/thread/process.cpp | 78 |
3 files changed, 91 insertions, 3 deletions
diff --git a/src/pal/src/include/pal/process.h b/src/pal/src/include/pal/process.h index d3a2ad4576..1f299271e4 100644 --- a/src/pal/src/include/pal/process.h +++ b/src/pal/src/include/pal/process.h @@ -152,6 +152,17 @@ Function: --*/ void PROCCleanupProcess(BOOL bTerminateUnconditionally); +/*++ +Function: + InitializeFlushProcessWriteBuffers + +Abstract + This function initializes data structures needed for the FlushProcessWriteBuffers +Return + TRUE if it succeeded, FALSE otherwise +--*/ +BOOL InitializeFlushProcessWriteBuffers(); + #if HAVE_MACH_EXCEPTIONS /*++ Function: diff --git a/src/pal/src/init/pal.cpp b/src/pal/src/init/pal.cpp index 93b6c038f8..275d78dd83 100644 --- a/src/pal/src/init/pal.cpp +++ b/src/pal/src/init/pal.cpp @@ -670,6 +670,11 @@ PAL_InitializeCoreCLR( return ERROR_DLL_INIT_FAILED; } + if (!InitializeFlushProcessWriteBuffers()) + { + return ERROR_GEN_FAILURE; + } + if (!fStayInPAL) { PAL_Leave(PAL_BoundaryTop); diff --git a/src/pal/src/thread/process.cpp b/src/pal/src/thread/process.cpp index 78477008cc..7097e093b5 100644 --- a/src/pal/src/thread/process.cpp +++ b/src/pal/src/thread/process.cpp @@ -31,6 +31,7 @@ Abstract: #include "pal/dbgmsg.h" #include "pal/utils.h" #include "pal/misc.h" +#include "pal/virtual.h" #include <errno.h> #if HAVE_POLL @@ -39,6 +40,7 @@ Abstract: #include "pal/fakepoll.h" #endif // HAVE_POLL +#include <sys/mman.h> #include <sys/types.h> #include <signal.h> #include <sys/wait.h> @@ -85,6 +87,16 @@ CObjectType CorUnix::otProcess( CObjectType::NoOwner ); +// +// Helper memory page used by the FlushProcessWriteBuffers +// +static int s_helperPage[VIRTUAL_PAGE_SIZE / sizeof(int)] __attribute__((aligned(VIRTUAL_PAGE_SIZE))); + +// +// Mutex to make the FlushProcessWriteBuffersMutex thread safe +// +pthread_mutex_t flushProcessWriteBuffersMutex; + CAllowedObjectTypes aotProcess(otiProcess); // @@ -1746,6 +1758,50 @@ OpenProcessExit: /*++ Function: + InitializeFlushProcessWriteBuffers + +Abstract + This function initializes data structures needed for the FlushProcessWriteBuffers +Return + TRUE if it succeeded, FALSE otherwise +--*/ +BOOL InitializeFlushProcessWriteBuffers() +{ + // Verify that the s_helperPage is really aligned to the VIRTUAL_PAGE_SIZE + _ASSERTE((((SIZE_T)s_helperPage) & (VIRTUAL_PAGE_SIZE - 1)) == 0); + + // Locking the page ensures that it stays in memory during the two mprotect + // calls in the FlushProcessWriteBuffers below. If the page was unmapped between + // those calls, they would not have the expected effect of generating IPI. + int status = mlock(s_helperPage, VIRTUAL_PAGE_SIZE); + + if (status != 0) + { + return FALSE; + } + + status = pthread_mutex_init(&flushProcessWriteBuffersMutex, NULL); + if (status != 0) + { + munlock(s_helperPage, VIRTUAL_PAGE_SIZE); + } + + return status == 0; +} + +#define FATAL_ASSERT(e, msg) \ + do \ + { \ + if (!(e)) \ + { \ + fprintf(stderr, "FATAL ERROR: " msg); \ + abort(); \ + } \ + } \ + while(0) + +/*++ +Function: FlushProcessWriteBuffers See MSDN doc. @@ -1753,9 +1809,25 @@ See MSDN doc. VOID PALAPI FlushProcessWriteBuffers() -{ - // UNIXTODO: Implement this. There seems to be no equivalent on Linux - // that could be used in user mode code. +{ + int status = pthread_mutex_lock(&flushProcessWriteBuffersMutex); + FATAL_ASSERT(status == 0, "Failed to lock the flushProcessWriteBuffersMutex lock"); + + // Changing a helper memory page protection from read / write to no access + // causes the OS to issue IPI to flush TLBs on all processors. This also + // results in flushing the processor buffers. + status = mprotect(s_helperPage, VIRTUAL_PAGE_SIZE, PROT_READ | PROT_WRITE); + FATAL_ASSERT(status == 0, "Failed to change helper page protection to read / write"); + + // Ensure that the page is dirty before we change the protection so that + // we prevent the OS from skipping the global TLB flush. + InterlockedIncrement(s_helperPage); + + status = mprotect(s_helperPage, VIRTUAL_PAGE_SIZE, PROT_NONE); + FATAL_ASSERT(status == 0, "Failed to change helper page protection to no access"); + + status = pthread_mutex_unlock(&flushProcessWriteBuffersMutex); + FATAL_ASSERT(status == 0, "Failed to unlock the flushProcessWriteBuffersMutex lock"); } /*++ |