mercurial/cext/osutil.c
changeset 51738 b619ba39d10a
parent 49275 c6a3243567b6
--- a/mercurial/cext/osutil.c	Thu Jul 25 14:40:38 2024 -0400
+++ b/mercurial/cext/osutil.c	Tue Jul 09 20:08:48 2024 +0200
@@ -36,6 +36,12 @@
 #endif
 #endif
 
+#ifndef _WIN32
+#include <sys/mman.h>
+#include <pthread.h>
+#endif
+
+
 #ifdef __APPLE__
 #include <sys/attr.h>
 #include <sys/vnode.h>
@@ -1203,6 +1209,49 @@
 }
 #endif
 
+#ifdef MADV_POPULATE_READ
+
+typedef struct {
+    void * mmap_address;
+    size_t length;
+} mmap_info;
+
+static void _mmap_populate(mmap_info *info) {
+    /* We explicitly does not check the return value as we don't care about it.
+     * the madvise is here to help performance and we don't care if it fails
+     * (for example because the mapping is no longer valid) */
+    void * mmap_address = info->mmap_address;
+    size_t length = info->length;
+    free(info);
+    madvise(mmap_address, length, MADV_POPULATE_READ);
+}
+
+static PyObject *background_mmap_populate(PyObject *self, PyObject *mmap) {
+    Py_buffer b;
+    pthread_t thread_id;
+    mmap_info *info;
+    if (PyObject_GetBuffer(mmap, &b, PyBUF_CONTIG_RO | PyBUF_C_CONTIGUOUS) == -1) {
+        return NULL;
+    }
+    info = (mmap_info *)malloc(sizeof(mmap_info));
+    info->mmap_address=b.buf;
+    info->length=b.len;
+    /* note: for very large map, we could spin multiple thread populating
+     * different area */
+    pthread_create(&thread_id, NULL, (void *) &_mmap_populate, info);
+    /* We don't keep track of this thread as it is fine for it to die when we
+     * exit. */
+    pthread_detach(thread_id);
+    /* We release the PyBuffer in the main thread to let the object be garbage
+     * collected as soon as possible. This might result in the memory map being
+     * closed while the background thread is working. That will result in a
+     * error in the background thread we can ignore. */
+    PyBuffer_Release(&b);
+	Py_RETURN_NONE;
+}
+
+#endif
+
 static char osutil_doc[] = "Native operating system services.";
 
 static PyMethodDef methods[] = {
@@ -1237,6 +1286,10 @@
 		"Is a CoreGraphics session available?"
 	},
 #endif
+#ifdef MADV_POPULATE_READ
+	{"background_mmap_populate", (PyCFunction)background_mmap_populate, METH_O,
+	 "populate a mmap in the background\n"},
+#endif
 	{NULL, NULL}
 };