[pypy-commit] stmgc c7-fork: ...

arigo noreply at buildbot.pypy.org
Wed Mar 19 08:48:46 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: c7-fork
Changeset: r1073:769b3113998d
Date: 2014-03-19 08:48 +0100
http://bitbucket.org/pypy/stmgc/changeset/769b3113998d/

Log:	...

diff --git a/c7/stm/forksupport.c b/c7/stm/forksupport.c
--- a/c7/stm/forksupport.c
+++ b/c7/stm/forksupport.c
@@ -4,7 +4,7 @@
 
 
 /* XXX this is currently not doing copy-on-write, but simply forces a
-   copy of all shared pages as soon as fork() is called. */
+   copy of all pages as soon as fork() is called. */
 
 
 static char *fork_big_copy = NULL;
@@ -12,8 +12,6 @@
 static bool fork_was_in_transaction;
 
 static char *setup_mmap(char *reason);            /* forward, in setup.c */
-static void do_or_redo_setup_after_fork(void);    /* forward, in setup.c */
-static void do_or_redo_teardown_after_fork(void); /* forward, in setup.c */
 static pthread_t *_get_cpth(stm_thread_local_t *);/* forward, in setup.c */
 
 
@@ -31,37 +29,34 @@
 
     dprintf(("forksupport_prepare\n"));
 
-    fork_this_tl = NULL;
+    stm_thread_local_t *this_tl = NULL;
     stm_thread_local_t *tl = stm_all_thread_locals;
     do {
         if (pthread_equal(*_get_cpth(tl), pthread_self())) {
-            if (fork_this_tl != NULL)
+            if (this_tl != NULL)
                 stm_fatalerror("fork(): found several stm_thread_local_t"
                                " from the same thread");
-            fork_this_tl = tl;
+            this_tl = tl;
         }
         tl = tl->next;
     } while (tl != stm_all_thread_locals);
 
-    if (fork_this_tl == NULL)
+    if (this_tl == NULL)
         stm_fatalerror("fork(): found no stm_thread_local_t from this thread");
     s_mutex_unlock();
 
-    /* Run a commit without releasing the mutex at the end; if necessary,
-       actually start a dummy inevitable transaction for this
-    */
-    fork_was_in_transaction = _stm_in_transaction(fork_this_tl);
-    if (!fork_was_in_transaction)
-        stm_start_inevitable_transaction(fork_this_tl);
-    _stm_commit_transaction(/*keep_the_lock_at_the_end =*/ 1);
+    bool was_in_transaction = _stm_in_transaction(this_tl);
+    if (was_in_transaction) {
+        stm_become_inevitable("fork");
+        /* Note that the line above can still fail and abort, which should
+           be fine */
+    }
+    else {
+        stm_start_inevitable_transaction(this_tl);
+    }
 
-    printf("fork_was_in_transaction: %d\n"
-           "fork_this_tl->associated_segment_num: %d\n",
-           (int)fork_was_in_transaction,
-           (int)fork_this_tl->associated_segment_num);
-
-    /* Note that the commit can still fail and abort, which should be fine */
-
+    s_mutex_lock();
+    synchronize_all_threads();
     mutex_pages_lock();
 
     /* Make a new mmap at some other address, but of the same size as
@@ -79,7 +74,7 @@
     }
 
     /* Copy all the data from the two ranges of objects (large, small)
-       into the new mmap --- but only the shared objects
+       into the new mmap
     */
     uintptr_t pagenum, endpagenum;
     pagenum = END_NURSERY_PAGE;   /* starts after the nursery */
@@ -100,15 +95,32 @@
             endpagenum = NB_PAGES;
         }
 
-        pagecopy(big_copy + pagenum * 4096UL,
-                 stm_object_pages + pagenum * 4096UL);
+        char *src = stm_object_pages + pagenum * 4096UL;
+        char *dst = big_copy + pagenum * 4096UL;
+        pagecopy(dst, src);
+
+        struct page_shared_s ps = pages_privatized[pagenum - PAGE_FLAG_START];
+        if (ps.by_segment != 0) {
+            long j;
+            for (j = 0; j < NB_SEGMENTS; j++) {
+                src += NB_PAGES * 4096UL;
+                dst += NB_PAGES * 4096UL;
+                if (ps.by_segment & (1 << j)) {
+                    pagecopy(dst, src);
+                }
+            }
+        }
         pagenum++;
     }
 
     assert(fork_big_copy == NULL);
     fork_big_copy = big_copy;
+    fork_this_tl = this_tl;
+    fork_was_in_transaction = was_in_transaction;
 
     assert(_has_mutex());
+    printf("forksupport_prepare: from %p %p\n", fork_this_tl,
+           fork_this_tl->creating_pthread[0]);
 }
 
 static void forksupport_parent(void)
@@ -116,8 +128,10 @@
     if (stm_object_pages == NULL)
         return;
 
+    printf("forksupport_parent: continuing to run %p %p\n", fork_this_tl,
+           fork_this_tl->creating_pthread[0]);
+    assert(_has_mutex());
     assert(_is_tl_registered(fork_this_tl));
-    assert(_has_mutex());
 
     /* In the parent, after fork(), we can simply forget about the big copy
        that we made for the child.
@@ -125,22 +139,33 @@
     assert(fork_big_copy != NULL);
     munmap(fork_big_copy, TOTAL_MEMORY);
     fork_big_copy = NULL;
+    bool was_in_transaction = fork_was_in_transaction;
+
+    mutex_pages_unlock();
+    s_mutex_unlock();
+
+    if (!was_in_transaction) {
+        stm_commit_transaction();
+    }
 
     dprintf(("forksupport_parent: continuing to run\n"));
+}
 
-    mutex_pages_unlock();
+static void fork_abort_thread(long i)
+{
+    struct stm_priv_segment_info_s *pr = get_priv_segment(i);
+    dprintf(("forksupport_child: abort in seg%ld\n", i));
+    assert(pr->pub.running_thread->associated_segment_num == i);
+    assert(pr->transaction_state == TS_REGULAR);
+    set_gs_register(get_segment_base(i));
 
-    printf("AFTER: fork_was_in_transaction: %d\n"
-           "fork_this_tl->associated_segment_num: %d\n",
-           (int)fork_was_in_transaction,
-           (int)fork_this_tl->associated_segment_num);
-
-    if (fork_was_in_transaction) {
-        _stm_start_transaction(fork_this_tl, NULL,
-                               /*already_got_the_lock =*/ 1);
-    }
-    else {
-        s_mutex_unlock();
+    stm_jmpbuf_t jmpbuf;
+    if (__builtin_setjmp(jmpbuf) == 0) {
+        pr->pub.jmpbuf_ptr = &jmpbuf;
+#ifndef NDEBUG
+        pr->running_pthread = pthread_self();
+#endif
+        stm_abort_transaction();
     }
 }
 
@@ -148,7 +173,6 @@
 {
     if (stm_object_pages == NULL)
         return;
-    abort();
 
     /* this new process contains no other thread, so we can
        just release these locks early */
@@ -170,7 +194,6 @@
     /* Unregister all other stm_thread_local_t, mostly as a way to free
        the memory used by the shadowstacks
      */
-    assert(fork_this_tl != NULL);
     while (stm_all_thread_locals->next != stm_all_thread_locals) {
         if (stm_all_thread_locals == fork_this_tl)
             stm_unregister_thread_local(stm_all_thread_locals->next);
@@ -179,37 +202,58 @@
     }
     assert(stm_all_thread_locals == fork_this_tl);
 
-    /* Restore a few things: the new pthread_self(), and the %gs
-       register (although I suppose it should be preserved by fork())
-    */
-    *_get_cpth(fork_this_tl) = pthread_self();
-    set_gs_register(get_segment_base(fork_this_tl->associated_segment_num));
-
-    /* Call a subset of stm_teardown() / stm_setup() to free and
-       recreate the necessary data in all segments, and to clean up some
-       of the global data like the big arrays that don't make sense any
-       more.  We keep other things like the smallmalloc and largemalloc
-       internal state.
-    */
-    do_or_redo_teardown_after_fork();
-    do_or_redo_setup_after_fork();
-
     /* Make all pages shared again.
      */
-    mutex_pages_lock();
-    uintptr_t start = END_NURSERY_PAGE;
-    uintptr_t stop  = (uninitialized_page_start - stm_object_pages) / 4096UL;
-    pages_initialize_shared(start, stop - start);
-    start = (uninitialized_page_stop - stm_object_pages) / 4096UL;
-    stop = NB_PAGES;
-    pages_initialize_shared(start, stop - start);
-    mutex_pages_unlock();
+    uintptr_t pagenum, endpagenum;
+    pagenum = END_NURSERY_PAGE;   /* starts after the nursery */
+    endpagenum = (uninitialized_page_start - stm_object_pages) / 4096UL;
 
-    /* Now restart the transaction if needed
+    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 (endpagenum == NB_PAGES)
+                break;   /* done */
+        }
+
+        struct page_shared_s ps = pages_privatized[pagenum - PAGE_FLAG_START];
+        long j;
+        for (j = 0; j < NB_SEGMENTS; j++) {
+            if (!(ps.by_segment & (1 << j))) {
+                _page_do_reshare(j + 1, pagenum);
+            }
+        }
+        pagenum++;
+    }
+
+    /* Force the interruption of other running segments
      */
-    if (fork_was_in_transaction)
-        stm_start_inevitable_transaction(fork_this_tl);
+    long i;
+    for (i = 1; i <= NB_SEGMENTS; i++) {
+        struct stm_priv_segment_info_s *pr = get_priv_segment(i);
+        if (pr->pub.running_thread != NULL &&
+            pr->pub.running_thread != fork_this_tl) {
+            fork_abort_thread(i);
+        }
+    }
 
+    /* Restore a few things: the new pthread_self(), and the %gs
+       register */
+    int segnum = fork_this_tl->associated_segment_num;
+    assert(1 <= segnum && segnum <= NB_SEGMENTS);
+    *_get_cpth(fork_this_tl) = pthread_self();
+    set_gs_register(get_segment_base(segnum));
+    assert(STM_SEGMENT->segment_num == segnum);
+
+    if (!fork_was_in_transaction) {
+        stm_commit_transaction();
+    }
+
+    /* Done */
     dprintf(("forksupport_child: running one thread now\n"));
 }
 
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
--- a/c7/stm/pages.c
+++ b/c7/stm/pages.c
@@ -146,6 +146,13 @@
     mutex_pages_unlock();
 }
 
+static void _page_do_reshare(long segnum, uintptr_t pagenum)
+{
+    char *segment_base = get_segment_base(segnum);
+    d_remap_file_pages(segment_base + pagenum * 4096UL,
+                       4096, pagenum);
+}
+
 static void page_reshare(uintptr_t pagenum)
 {
     struct page_shared_s ps = pages_privatized[pagenum - PAGE_FLAG_START];
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -38,6 +38,7 @@
 static void pages_initialize_shared(uintptr_t pagenum, uintptr_t count);
 static void page_privatize(uintptr_t pagenum);
 static void page_reshare(uintptr_t pagenum);
+static void _page_do_reshare(long segnum, uintptr_t pagenum);
 
 /* Note: don't ever do "mutex_pages_lock(); mutex_lock()" in that order */
 static void mutex_pages_lock(void);
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -69,7 +69,7 @@
     /* the next fields are handled internally by the library */
     int associated_segment_num;
     struct stm_thread_local_s *prev, *next;
-    long creating_pthread[4];
+    void *creating_pthread[2];
 } stm_thread_local_t;
 
 /* this should use llvm's coldcc calling convention,


More information about the pypy-commit mailing list