Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit