Fault in all the SHM pages during startup

Change-Id: I8694e2dc80e1871d2e4444795bb7727f6c31ca5c
diff --git a/aos/events/shm_event_loop.cc b/aos/events/shm_event_loop.cc
index b2ccca6..97c9963 100644
--- a/aos/events/shm_event_loop.cc
+++ b/aos/events/shm_event_loop.cc
@@ -61,6 +61,31 @@
   return ShmFolder(channel) + channel->type()->str() + ".v2";
 }
 
+void PageFaultData(char *data, size_t size) {
+  // This just has to divide the actual page size. Being smaller will make this
+  // a bit slower than necessary, but not much. 1024 is a pretty conservative
+  // choice (most pages are probably 4096).
+  static constexpr size_t kPageSize = 1024;
+  const size_t pages = (size + kPageSize - 1) / kPageSize;
+  for (size_t i = 0; i < pages; ++i) {
+    char zero = 0;
+    // We need to ensure there's a writable pagetable entry, but avoid modifying
+    // the data.
+    //
+    // Even if you lock the data into memory, some kernels still seem to lazily
+    // create the actual pagetable entries. This means we need to somehow
+    // "write" to the page.
+    //
+    // Also, this takes place while other processes may be concurrently
+    // opening/initializing the memory, so we need to avoid corrupting that.
+    //
+    // This is the simplest operation I could think of which achieves that:
+    // "store 0 if it's already 0".
+    __atomic_compare_exchange_n(&data[i * kPageSize], &zero, 0, true,
+                                __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+  }
+}
+
 class MMapedQueue {
  public:
   MMapedQueue(const Channel *channel,
@@ -112,6 +137,7 @@
     data_ = mmap(NULL, size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     PCHECK(data_ != MAP_FAILED);
     PCHECK(close(fd) == 0);
+    PageFaultData(static_cast<char *>(data_), size_);
 
     ipc_lib::InitializeLocklessQueueMemory(memory(), config_);
   }