@@ -61,6 +61,24 @@ SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so d
61
61
#include < stdint.h>
62
62
#include < dlfcn.h>
63
63
64
+ #ifdef __linux__
65
+ #include < sys/syscall.h> // __NR_membarrier
66
+ // Ensure __NR_membarrier is defined for portable builds.
67
+ # if !defined(__NR_membarrier)
68
+ # if defined(__amd64__)
69
+ # define __NR_membarrier 324
70
+ # elif defined(__i386__)
71
+ # define __NR_membarrier 375
72
+ # elif defined(__arm__)
73
+ # define __NR_membarrier 389
74
+ # elif defined(__aarch64__)
75
+ # define __NR_membarrier 283
76
+ # elif
77
+ # error Unknown architecture
78
+ # endif
79
+ # endif
80
+ #endif
81
+
64
82
#ifdef __APPLE__
65
83
#include < sys/sysctl.h>
66
84
#endif
@@ -97,6 +115,32 @@ CObjectType CorUnix::otProcess(
97
115
CObjectType::NoOwner
98
116
);
99
117
118
+ //
119
+ // Helper membarrier function
120
+ //
121
+ #ifdef __NR_membarrier
122
+ # define membarrier (...) syscall(__NR_membarrier, __VA_ARGS__)
123
+ #else
124
+ # define membarrier (...) -ENOSYS
125
+ #endif
126
+
127
+ enum membarrier_cmd
128
+ {
129
+ MEMBARRIER_CMD_QUERY = 0 ,
130
+ MEMBARRIER_CMD_GLOBAL = (1 << 0 ),
131
+ MEMBARRIER_CMD_GLOBAL_EXPEDITED = (1 << 1 ),
132
+ MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED = (1 << 2 ),
133
+ MEMBARRIER_CMD_PRIVATE_EXPEDITED = (1 << 3 ),
134
+ MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = (1 << 4 ),
135
+ MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 5 ),
136
+ MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 6 )
137
+ };
138
+
139
+ //
140
+ // Tracks if the OS supports FlushProcessWriteBuffers using membarrier
141
+ //
142
+ static int s_flushUsingMemBarrier = 0 ;
143
+
100
144
//
101
145
// Helper memory page used by the FlushProcessWriteBuffers
102
146
//
@@ -3133,12 +3177,27 @@ BOOL
3133
3177
InitializeFlushProcessWriteBuffers ()
3134
3178
{
3135
3179
_ASSERTE (s_helperPage == 0 );
3180
+ _ASSERTE (s_flushUsingMemBarrier == 0 );
3181
+
3182
+ // Starting with Linux kernel 4.14, process memory barriers can be generated
3183
+ // using MEMBARRIER_CMD_PRIVATE_EXPEDITED.
3184
+ int mask = membarrier (MEMBARRIER_CMD_QUERY, 0 );
3185
+ if (mask >= 0 &&
3186
+ mask & MEMBARRIER_CMD_PRIVATE_EXPEDITED)
3187
+ {
3188
+ // Register intent to use the private expedited command.
3189
+ if (membarrier (MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0 ) == 0 )
3190
+ {
3191
+ s_flushUsingMemBarrier = TRUE ;
3192
+ return TRUE ;
3193
+ }
3194
+ }
3136
3195
3137
3196
s_helperPage = static_cast <int *>(mmap (0 , GetVirtualPageSize (), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1 , 0 ));
3138
3197
3139
3198
if (s_helperPage == MAP_FAILED)
3140
3199
{
3141
- return false ;
3200
+ return FALSE ;
3142
3201
}
3143
3202
3144
3203
// Verify that the s_helperPage is really aligned to the GetVirtualPageSize()
@@ -3184,24 +3243,32 @@ VOID
3184
3243
PALAPI
3185
3244
FlushProcessWriteBuffers ()
3186
3245
{
3187
- int status = pthread_mutex_lock (&flushProcessWriteBuffersMutex);
3188
- FATAL_ASSERT (status == 0 , " Failed to lock the flushProcessWriteBuffersMutex lock" );
3246
+ if (s_flushUsingMemBarrier)
3247
+ {
3248
+ int status = membarrier (MEMBARRIER_CMD_PRIVATE_EXPEDITED, 0 );
3249
+ FATAL_ASSERT (status == 0 , " Failed to flush using membarrier" );
3250
+ }
3251
+ else
3252
+ {
3253
+ int status = pthread_mutex_lock (&flushProcessWriteBuffersMutex);
3254
+ FATAL_ASSERT (status == 0 , " Failed to lock the flushProcessWriteBuffersMutex lock" );
3189
3255
3190
- // Changing a helper memory page protection from read / write to no access
3191
- // causes the OS to issue IPI to flush TLBs on all processors. This also
3192
- // results in flushing the processor buffers.
3193
- status = mprotect (s_helperPage, GetVirtualPageSize (), PROT_READ | PROT_WRITE);
3194
- FATAL_ASSERT (status == 0 , " Failed to change helper page protection to read / write" );
3256
+ // Changing a helper memory page protection from read / write to no access
3257
+ // causes the OS to issue IPI to flush TLBs on all processors. This also
3258
+ // results in flushing the processor buffers.
3259
+ status = mprotect (s_helperPage, GetVirtualPageSize (), PROT_READ | PROT_WRITE);
3260
+ FATAL_ASSERT (status == 0 , " Failed to change helper page protection to read / write" );
3195
3261
3196
- // Ensure that the page is dirty before we change the protection so that
3197
- // we prevent the OS from skipping the global TLB flush.
3198
- InterlockedIncrement (s_helperPage);
3262
+ // Ensure that the page is dirty before we change the protection so that
3263
+ // we prevent the OS from skipping the global TLB flush.
3264
+ InterlockedIncrement (s_helperPage);
3199
3265
3200
- status = mprotect (s_helperPage, GetVirtualPageSize (), PROT_NONE);
3201
- FATAL_ASSERT (status == 0 , " Failed to change helper page protection to no access" );
3266
+ status = mprotect (s_helperPage, GetVirtualPageSize (), PROT_NONE);
3267
+ FATAL_ASSERT (status == 0 , " Failed to change helper page protection to no access" );
3202
3268
3203
- status = pthread_mutex_unlock (&flushProcessWriteBuffersMutex);
3204
- FATAL_ASSERT (status == 0 , " Failed to unlock the flushProcessWriteBuffersMutex lock" );
3269
+ status = pthread_mutex_unlock (&flushProcessWriteBuffersMutex);
3270
+ FATAL_ASSERT (status == 0 , " Failed to unlock the flushProcessWriteBuffersMutex lock" );
3271
+ }
3205
3272
}
3206
3273
3207
3274
/* ++
0 commit comments