Author: Armin Rigo <ar...@tunes.org> Branch: queue Changeset: r1864:0a10e04f2119 Date: 2015-06-18 18:50 +0200 http://bitbucket.org/pypy/stmgc/changeset/0a10e04f2119/
Log: hg merge default diff --git a/c8/stm/core.c b/c8/stm/core.c --- a/c8/stm/core.c +++ b/c8/stm/core.c @@ -495,6 +495,32 @@ static void readd_wb_executed_flags(void); static void check_all_write_barrier_flags(char *segbase, struct list_s *list); +static void wait_for_inevitable(void) +{ + intptr_t detached = 0; + + s_mutex_lock(); + wait_some_more: + if (safe_point_requested()) { + /* XXXXXX if the safe point below aborts, in + _validate_and_attach(), 'new' leaks */ + enter_safe_point_if_requested(); + } + else if (STM_PSEGMENT->last_commit_log_entry->next == INEV_RUNNING) { + /* loop until C_SEGMENT_FREE_OR_SAFE_POINT_REQ is signalled, but + try to detach an inevitable transaction regularly */ + detached = fetch_detached_transaction(); + if (detached == 0) { + if (!cond_wait_timeout(C_SEGMENT_FREE_OR_SAFE_POINT_REQ, 0.00001)) + goto wait_some_more; + } + } + s_mutex_unlock(); + + if (detached != 0) + commit_fetched_detached_transaction(detached); +} + /* This is called to do stm_validate() and then attach 'new' at the head of the 'commit_log_root' chained list. This function sleeps and retries until it succeeds or aborts. @@ -523,24 +549,10 @@ #endif if (STM_PSEGMENT->last_commit_log_entry->next == INEV_RUNNING) { - s_mutex_lock(); - if (safe_point_requested()) { - /* XXXXXX if the safe point below aborts, 'new' leaks */ - enter_safe_point_if_requested(); - } - else if (STM_PSEGMENT->last_commit_log_entry->next == INEV_RUNNING) { - cond_wait(C_SEGMENT_FREE_OR_SAFE_POINT); - } - s_mutex_unlock(); + wait_for_inevitable(); goto retry_from_start; /* redo _stm_validate() now */ } - intptr_t detached = fetch_detached_transaction(); - if (detached != 0) { - commit_fetched_detached_transaction(detached); - goto retry_from_start; - } - /* we must not remove the WB_EXECUTED flags before validation as it is part of a condition in import_objects() called by copy_bk_objs_in_page_from to not overwrite our modifications. @@ -1119,7 +1131,7 @@ { assert(!_stm_in_transaction(tl)); - while (!acquire_thread_segment(tl)) {} + acquire_thread_segment(tl); /* GS invalid before this point! */ assert(STM_PSEGMENT->safe_point == SP_NO_TRANSACTION); @@ -1571,13 +1583,33 @@ timing_become_inevitable(); /* for tests: another transaction */ stm_abort_transaction(); /* is already inevitable, abort */ #endif + + bool timed_out = false; + s_mutex_lock(); if (any_soon_finished_or_inevitable_thread_segment() && !safe_point_requested()) { - cond_wait(C_SEGMENT_FREE_OR_SAFE_POINT); + + /* wait until C_SEGMENT_FREE_OR_SAFE_POINT_REQ is signalled */ + if (!cond_wait_timeout(C_SEGMENT_FREE_OR_SAFE_POINT_REQ, + 0.000054321)) + timed_out = true; } s_mutex_unlock(); - num_waits++; + + if (timed_out) { + /* try to detach another inevitable transaction, but + only after waiting a bit. This is necessary to avoid + deadlocks in some situations, which are hopefully + not too common. We don't want two threads constantly + detaching each other. */ + intptr_t detached = fetch_detached_transaction(); + if (detached != 0) + commit_fetched_detached_transaction(detached); + } + else { + num_waits++; + } goto retry_from_start; } if (!_validate_and_turn_inevitable()) diff --git a/c8/stm/sync.c b/c8/stm/sync.c --- a/c8/stm/sync.c +++ b/c8/stm/sync.c @@ -203,10 +203,11 @@ #endif -static bool acquire_thread_segment(stm_thread_local_t *tl) +static void acquire_thread_segment(stm_thread_local_t *tl) { /* This function acquires a segment for the currently running thread, and set up the GS register if it changed. */ + retry_from_start: assert(_has_mutex()); assert(_is_tl_registered(tl)); @@ -240,13 +241,13 @@ } } /* No segment available. Wait until release_thread_segment() - signals that one segment has been freed. */ + signals that one segment has been freed. Note that we prefer + waiting rather than detaching an inevitable transaction, here. */ timing_event(tl, STM_WAIT_FREE_SEGMENT); cond_wait(C_SEGMENT_FREE); timing_event(tl, STM_WAIT_DONE); - /* Return false to the caller, which will call us again */ - return false; + goto retry_from_start; got_num: OPT_ASSERT(num >= 0 && num < NB_SEGMENTS-1); @@ -257,7 +258,6 @@ assert(!in_transaction(tl)); STM_SEGMENT->running_thread = tl; assert(in_transaction(tl)); - return true; } static void release_thread_segment(stm_thread_local_t *tl) @@ -266,7 +266,7 @@ assert(_has_mutex()); cond_signal(C_SEGMENT_FREE); - cond_broadcast(C_SEGMENT_FREE_OR_SAFE_POINT); /* often no listener */ + cond_broadcast(C_SEGMENT_FREE_OR_SAFE_POINT_REQ); /* often no listener */ assert(STM_SEGMENT->running_thread == tl); segnum = STM_SEGMENT->segment_num; @@ -362,7 +362,7 @@ assert(!pause_signalled); pause_signalled = true; dprintf(("request to pause\n")); - cond_broadcast(C_SEGMENT_FREE_OR_SAFE_POINT); + cond_broadcast(C_SEGMENT_FREE_OR_SAFE_POINT_REQ); } static inline long count_other_threads_sp_running(void) diff --git a/c8/stm/sync.h b/c8/stm/sync.h --- a/c8/stm/sync.h +++ b/c8/stm/sync.h @@ -5,7 +5,7 @@ C_AT_SAFE_POINT, C_REQUEST_REMOVED, C_SEGMENT_FREE, - C_SEGMENT_FREE_OR_SAFE_POINT, + C_SEGMENT_FREE_OR_SAFE_POINT_REQ, C_QUEUE_OLD_ENTRIES, C_QUEUE_FINISHED_MORE_TASKS, _C_TOTAL @@ -25,7 +25,7 @@ /* acquire and release one of the segments for running the given thread (must have the mutex acquired!) */ -static bool acquire_thread_segment(stm_thread_local_t *tl); +static void acquire_thread_segment(stm_thread_local_t *tl); static void release_thread_segment(stm_thread_local_t *tl); static void soon_finished_or_inevitable_thread_segment(void); static bool any_soon_finished_or_inevitable_thread_segment(void); diff --git a/c8/test/test_hashtable.py b/c8/test/test_hashtable.py --- a/c8/test/test_hashtable.py +++ b/c8/test/test_hashtable.py @@ -46,6 +46,8 @@ try: assert lib._get_type_id(obj) == 421419 self.seen_hashtables -= 1 + h = get_hashtable(obj) + lib.stm_hashtable_free(h) except: self.errors.append(sys.exc_info()[2]) raise _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit