Author: Armin Rigo <ar...@tunes.org>
Branch: c7-fork
Changeset: r1065:f467a519f7b6
Date: 2014-03-18 10:29 +0100
http://bitbucket.org/pypy/stmgc/changeset/f467a519f7b6/

Log:    in-progress, maybe, who knows

diff --git a/c7/stm/forksupport.c b/c7/stm/forksupport.c
new file mode 100644
--- /dev/null
+++ b/c7/stm/forksupport.c
@@ -0,0 +1,94 @@
+#ifndef _STM_CORE_H_
+# error "must be compiled via stmgc.c"
+#endif
+
+
+/* XXX this is currently not doing copy-on-write, but simply forces a
+   copy of all shared pages as soon as fork() is called. */
+
+
+static char *fork_big_copy;
+
+
+static void forksupport_prepare(void)
+{
+    if (stm_object_pages == NULL)
+        return;
+
+    /* This silently assumes that fork() is not called from transactions.
+       It's hard to check though...
+     */
+    s_mutex_lock();
+
+    synchronize_all_threads();
+
+    mutex_pages_lock();
+
+    char *big_copy = setup_mmap("stmgc's fork support");
+
+    uintptr_t pagenum, endpagenum;
+    pagenum = END_NURSERY_PAGE;   /* starts after the nursery */
+    endpagenum = (uninitialized_page_start - stm_object_pages) / 4096UL;
+
+    while (1) {
+        if (UNLIKELY(pagenum == endpagenum)) {
+            /* we reach this point usually twice, because there are
+               more pages after 'uninitialized_page_stop' */
+            if (endpagenum == NB_PAGES)
+                break;   /* done */
+            pagenum = (uninitialized_page_stop - stm_object_pages) / 4096UL;
+            endpagenum = NB_PAGES;
+            if (pagenum == endpagenum)
+                break;   /* no pages in the 2nd section, so done too */
+        }
+
+        pagecopy(big_copy + pagenum * 4096UL,
+                 stm_object_pages + pagenum * 4096UL);
+        pagenum++;
+    }
+
+    assert(fork_big_copy == NULL);
+    fork_big_copy = big_copy;
+}
+
+static void forksupport_parent(void)
+{
+    if (stm_object_pages == NULL)
+        return;
+
+    assert(fork_big_copy != NULL);
+    munmap(fork_big_copy, TOTAL_MEMORY);
+    stm_object_pages = NULL;
+
+    mutex_pages_unlock();
+    s_mutex_unlock();
+}
+
+static void forksupport_child(void)
+{
+    if (stm_object_pages == NULL)
+        return;
+
+    mremap(fork_big_copy, TOTAL_MEMORY, TOTAL_MEMORY,
+           MREMAP_MAYMOVE | MREMAP_FIXED,
+           stm_object_pages);
+
+    ...; reset carefully a much bigger part of the state here :-(((
+    memset(pages_privatized, 0, sizeof(pages_privatized));
+
+    mutex_pages_unlock();
+    s_mutex_unlock();
+}
+
+
+static void setup_forksupport(void)
+{
+    static bool fork_support_ready = false;
+
+    if (!fork_support_ready) {
+        int res = pthread_atfork(forksupport_prepare, forksupport_parent,
+                                 forksupport_child);
+        assert(res == 0);
+        fork_support_ready = true;
+    }
+}
diff --git a/c7/stm/forksupport.h b/c7/stm/forksupport.h
new file mode 100644
--- /dev/null
+++ b/c7/stm/forksupport.h
@@ -0,0 +1,2 @@
+
+static void setup_forksupport(void);
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -39,6 +39,7 @@
 static void page_privatize(uintptr_t pagenum);
 static void page_reshare(uintptr_t pagenum);
 
+/* Note: don't ever do "mutex_pages_lock(); mutex_lock()" in that order */
 static void mutex_pages_lock(void);
 static void mutex_pages_unlock(void);
 static bool _has_mutex_pages(void) __attribute__((unused));
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -3,6 +3,38 @@
 #endif
 
 
+static char *setup_mmap(char *reason)
+{
+    char *result = mmap(NULL, TOTAL_MEMORY,
+                        PROT_READ | PROT_WRITE,
+                        MAP_PAGES_FLAGS, -1, 0);
+    if (result == MAP_FAILED)
+        stm_fatalerror("%s failed: %m\n", reason);
+
+    /* The segment 0 is not used to run transactions, but contains the
+       shared copy of the pages.  We mprotect all pages before so that
+       accesses fail, up to and including the pages corresponding to the
+       nurseries of the other segments. */
+    mprotect(result, END_NURSERY_PAGE * 4096UL, PROT_NONE);
+
+    long i;
+    for (i = 1; i <= NB_SEGMENTS; i++) {
+        char *segment_base = result + i * (NB_PAGES * 4096UL);
+
+        /* In each segment, the first page is where TLPREFIX'ed
+           NULL accesses land.  We mprotect it so that accesses fail. */
+        mprotect(segment_base, 4096, PROT_NONE);
+
+        /* Pages in range(2, FIRST_READMARKER_PAGE) are never used */
+        if (FIRST_READMARKER_PAGE > 2)
+            mprotect(segment_base + 8192,
+                     (FIRST_READMARKER_PAGE - 2) * 4096UL,
+                     PROT_NONE);
+    }
+
+    return result;
+}
+
 void stm_setup(void)
 {
     /* Check that some values are acceptable */
@@ -20,38 +52,18 @@
            (FIRST_READMARKER_PAGE * 4096UL));
     assert(_STM_FAST_ALLOC <= NB_NURSERY_PAGES * 4096);
 
-    stm_object_pages = mmap(NULL, TOTAL_MEMORY,
-                            PROT_READ | PROT_WRITE,
-                            MAP_PAGES_FLAGS, -1, 0);
-    if (stm_object_pages == MAP_FAILED)
-        stm_fatalerror("initial stm_object_pages mmap() failed: %m\n");
-
-    /* The segment 0 is not used to run transactions, but to contain the
-       shared copy of the pages.  We mprotect all pages before so that
-       accesses fail, up to and including the pages corresponding to the
-       nurseries of the other segments. */
-    mprotect(stm_object_pages, END_NURSERY_PAGE * 4096UL, PROT_NONE);
+    stm_object_pages = setup_mmap("initial stm_object_pages mmap()");
 
     long i;
     for (i = 1; i <= NB_SEGMENTS; i++) {
         char *segment_base = get_segment_base(i);
 
-        /* In each segment, the first page is where TLPREFIX'ed
-           NULL accesses land.  We mprotect it so that accesses fail. */
-        mprotect(segment_base, 4096, PROT_NONE);
-
         /* Fill the TLS page (page 1) with 0xDC, for debugging */
         memset(REAL_ADDRESS(segment_base, 4096), 0xDC, 4096);
         /* Make a "hole" at STM_PSEGMENT (which includes STM_SEGMENT) */
         memset(REAL_ADDRESS(segment_base, STM_PSEGMENT), 0,
                sizeof(*STM_PSEGMENT));
 
-        /* Pages in range(2, FIRST_READMARKER_PAGE) are never used */
-        if (FIRST_READMARKER_PAGE > 2)
-            mprotect(segment_base + 8192,
-                     (FIRST_READMARKER_PAGE - 2) * 4096UL,
-                     PROT_NONE);
-
         /* Initialize STM_PSEGMENT */
         struct stm_priv_segment_info_s *pr = get_priv_segment(i);
         assert(1 <= i && i < 255);   /* 255 is WL_VISITED in gcpage.c */
@@ -83,6 +95,7 @@
     setup_nursery();
     setup_gcpage();
     setup_pages();
+    setup_forksupport();
 }
 
 void stm_teardown(void)
diff --git a/c7/stmgc.c b/c7/stmgc.c
--- a/c7/stmgc.c
+++ b/c7/stmgc.c
@@ -13,6 +13,7 @@
 #include "stm/extra.h"
 #include "stm/fprintcolor.h"
 #include "stm/weakref.h"
+#include "stm/forksupport.h"
 
 #include "stm/misc.c"
 #include "stm/list.c"
@@ -30,3 +31,4 @@
 #include "stm/extra.c"
 #include "stm/fprintcolor.c"
 #include "stm/weakref.c"
+#include "stm/forksupport.c"
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to