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