Author: Armin Rigo <ar...@tunes.org>
Branch: c7-fork
Changeset: r1072:5b46d0dcbbfd
Date: 2014-03-19 07:28 +0100
http://bitbucket.org/pypy/stmgc/changeset/5b46d0dcbbfd/

Log:    intermediate

diff --git a/c7/demo/demo_random.c b/c7/demo/demo_random.c
--- a/c7/demo/demo_random.c
+++ b/c7/demo/demo_random.c
@@ -14,7 +14,7 @@
 #define THREAD_STARTS 300 // how many restarts of threads
 #define PREBUILT_ROOTS 3
 #define MAXROOTS 1000
-#define FORKS 3
+#define FORKS 1
 
 // SUPPORT
 struct node_s;
@@ -339,9 +339,22 @@
 
         if (p == (objptr_t)-1) {
             push_roots();
-            stm_commit_transaction();
 
-            if (arg) {
+            if (arg == NULL) {   /* common case */
+                stm_commit_transaction();
+                td.num_roots_at_transaction_start = td.num_roots;
+                if (get_rand(100) < 98) {
+                    STM_START_TRANSACTION(&stm_thread_local, here);
+                } else {
+                    stm_start_inevitable_transaction(&stm_thread_local);
+                }
+                td.num_roots = td.num_roots_at_transaction_start;
+                p = NULL;
+                pop_roots();
+                reload_roots();
+            }
+            else {
+                /* run a fork() inside the transaction */
                 printf("==========   FORK  =========\n");
                 arg = NULL;
                 pid_t child = fork();
@@ -355,19 +368,10 @@
                     num_forked_children++;
                 else
                     num_forked_children = 0;
+
+                pop_roots();
+                p = NULL;
             }
-
-            td.num_roots_at_transaction_start = td.num_roots;
-
-            if (get_rand(100) < 98) {
-                STM_START_TRANSACTION(&stm_thread_local, here);
-            } else {
-                stm_start_inevitable_transaction(&stm_thread_local);
-            }
-            td.num_roots = td.num_roots_at_transaction_start;
-            p = NULL;
-            pop_roots();
-            reload_roots();
         }
     }
     stm_commit_transaction();
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -164,11 +164,13 @@
     STM_SEGMENT->transaction_read_version = 1;
 }
 
-void _stm_start_transaction(stm_thread_local_t *tl, stm_jmpbuf_t *jmpbuf)
+void _stm_start_transaction(stm_thread_local_t *tl, stm_jmpbuf_t *jmpbuf,
+                            int already_got_the_lock)
 {
-    assert(!_stm_in_transaction(tl));
-
-    s_mutex_lock();
+    if (!already_got_the_lock) {
+        assert(!_stm_in_transaction(tl));
+        s_mutex_lock();
+    }
 
   retry:
     if (jmpbuf == NULL) {
@@ -447,7 +449,7 @@
     /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
 }
 
-void stm_commit_transaction(void)
+void _stm_commit_transaction(int keep_the_lock_at_the_end)
 {
     assert(!_has_mutex());
     assert(STM_PSEGMENT->safe_point == SP_RUNNING);
@@ -506,7 +508,8 @@
     _finish_transaction();
     /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
 
-    s_mutex_unlock();
+    if (!keep_the_lock_at_the_end)
+        s_mutex_unlock();
 }
 
 void stm_abort_transaction(void)
diff --git a/c7/stm/forksupport.c b/c7/stm/forksupport.c
--- a/c7/stm/forksupport.c
+++ b/c7/stm/forksupport.c
@@ -9,6 +9,7 @@
 
 static char *fork_big_copy = NULL;
 static stm_thread_local_t *fork_this_tl;
+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 */
@@ -21,23 +22,19 @@
     if (stm_object_pages == NULL)
         return;
 
-    /* This assumes that fork() is not called from transactions.
-       So far we attempt to check this by walking all stm_thread_local_t,
+    /* So far we attempt to check this by walking all stm_thread_local_t,
        marking the one from the current thread, and verifying that it's not
        running a transaction.  This assumes that the stm_thread_local_t is just
        a __thread variable, so never changes threads.
     */
     s_mutex_lock();
-    mutex_pages_lock();
 
-    dprintf(("forksupport_prepare: synchronized all threads\n"));
+    dprintf(("forksupport_prepare\n"));
 
     fork_this_tl = NULL;
     stm_thread_local_t *tl = stm_all_thread_locals;
     do {
         if (pthread_equal(*_get_cpth(tl), pthread_self())) {
-            if (_stm_in_transaction(tl))
-                stm_fatalerror("fork(): cannot be used inside a transaction");
             if (fork_this_tl != NULL)
                 stm_fatalerror("fork(): found several stm_thread_local_t"
                                " from the same thread");
@@ -48,6 +45,24 @@
 
     if (fork_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);
+
+    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 */
+
+    mutex_pages_lock();
 
     /* Make a new mmap at some other address, but of the same size as
        the standard mmap at stm_object_pages
@@ -92,6 +107,8 @@
 
     assert(fork_big_copy == NULL);
     fork_big_copy = big_copy;
+
+    assert(_has_mutex());
 }
 
 static void forksupport_parent(void)
@@ -99,6 +116,9 @@
     if (stm_object_pages == NULL)
         return;
 
+    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.
     */
@@ -109,37 +129,32 @@
     dprintf(("forksupport_parent: continuing to run\n"));
 
     mutex_pages_unlock();
-    s_mutex_unlock();
+
+    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();
+    }
 }
 
 static void forksupport_child(void)
 {
     if (stm_object_pages == NULL)
         return;
+    abort();
 
-    /* In the child, first unregister all other stm_thread_local_t,
-       mostly as a way to free the memory used by the shadowstacks
-     */
+    /* this new process contains no other thread, so we can
+       just release these locks early */
     mutex_pages_unlock();
     s_mutex_unlock();
 
-    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);
-        else
-            stm_unregister_thread_local(stm_all_thread_locals);
-    }
-    assert(stm_all_thread_locals == fork_this_tl);
-
-    /* Restore a few things in the child: 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));
-    fork_this_tl = NULL;
-
     /* Move the copy of the mmap over the old one, overwriting it
        and thus freeing the old mapping in this process
     */
@@ -152,6 +167,24 @@
         stm_fatalerror("after fork: mremap failed: %m");
     fork_big_copy = NULL;
 
+    /* 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);
+        else
+            stm_unregister_thread_local(stm_all_thread_locals);
+    }
+    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
@@ -172,6 +205,11 @@
     pages_initialize_shared(start, stop - start);
     mutex_pages_unlock();
 
+    /* Now restart the transaction if needed
+     */
+    if (fork_was_in_transaction)
+        stm_start_inevitable_transaction(fork_this_tl);
+
     dprintf(("forksupport_child: running one thread now\n"));
 }
 
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -78,7 +78,8 @@
 object_t *_stm_allocate_slowpath(ssize_t);
 object_t *_stm_allocate_external(ssize_t);
 void _stm_become_inevitable(const char*);
-void _stm_start_transaction(stm_thread_local_t *, stm_jmpbuf_t *);
+void _stm_start_transaction(stm_thread_local_t *, stm_jmpbuf_t *, int);
+void _stm_commit_transaction(int);
 void _stm_collectable_safe_point(void);
 
 /* for tests, but also used in duhton: */
@@ -257,17 +258,19 @@
    stm_jmpbuf_t). */
 #define STM_START_TRANSACTION(tl, jmpbuf)  ({                   \
     while (__builtin_setjmp(jmpbuf) == 1) { /*redo setjmp*/ }   \
-    _stm_start_transaction(tl, &jmpbuf);                        \
+    _stm_start_transaction(tl, &jmpbuf, 0);                     \
 })
 
 /* Start an inevitable transaction, if it's going to return from the
    current function immediately. */
 static inline void stm_start_inevitable_transaction(stm_thread_local_t *tl) {
-    _stm_start_transaction(tl, NULL);
+    _stm_start_transaction(tl, NULL, 0);
 }
 
 /* Commit a transaction. */
-void stm_commit_transaction(void);
+static inline void stm_commit_transaction(void) {
+    _stm_commit_transaction(0);
+}
 
 /* Abort the currently running transaction. */
 void stm_abort_transaction(void) __attribute__((noreturn));
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to