Author: Armin Rigo <ar...@tunes.org> Branch: c7-refactor Changeset: r743:8201455ea6be Date: 2014-02-15 23:41 +0100 http://bitbucket.org/pypy/stmgc/changeset/8201455ea6be/
Log: Progress diff --git a/c7/stm/contention.c b/c7/stm/contention.c --- a/c7/stm/contention.c +++ b/c7/stm/contention.c @@ -3,7 +3,7 @@ #endif -static void contention_management(uint8_t other_segment_num) +static void contention_management(uint8_t other_segment_num, bool wait) { /* A simple contention manager. Called when we do stm_write() on an object, but some other thread already holds the write @@ -16,12 +16,6 @@ struct stm_priv_segment_info_s* other_pseg; other_pseg = get_priv_segment(other_segment_num); - /* note: other_pseg is currently running a transaction, and it cannot - commit or abort unexpectedly, because to do that it would need to - suspend us. So the reading of other_pseg->start_time and - other_pseg->transaction_state is stable, with one exception: the - 'transaction_state' can go from TS_REGULAR to TS_INEVITABLE under - our feet. */ if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) { /* I'm inevitable, so the other is not. */ assert(other_pseg->transaction_state != TS_INEVITABLE); @@ -42,7 +36,7 @@ abort. */ abort_with_mutex(); } - else { + else if (wait) { /* otherwise, we will issue a safe point and wait: */ STM_PSEGMENT->safe_point = SP_SAFE_POINT; diff --git a/c7/stm/contention.h b/c7/stm/contention.h --- a/c7/stm/contention.h +++ b/c7/stm/contention.h @@ -1,2 +1,2 @@ -static void contention_management(uint8_t other_segment_num); +static void contention_management(uint8_t other_segment_num, bool wait); diff --git a/c7/stm/core.c b/c7/stm/core.c --- a/c7/stm/core.c +++ b/c7/stm/core.c @@ -7,8 +7,6 @@ static uint8_t write_locks[READMARKER_END - READMARKER_START]; -static void abort_with_mutex(void) __attribute__((noreturn)); - static void teardown_core(void) { memset(write_locks, 0, sizeof(write_locks)); @@ -58,7 +56,7 @@ By construction it should not be possible that the owner of the object is already us */ mutex_lock(); - contention_management(prev_owner - 1); + contention_management(prev_owner - 1, true); mutex_unlock(); } while (1); @@ -120,15 +118,31 @@ } -static bool detect_write_read_conflicts(void) +/************************************************************/ + +#if NB_SEGMENTS != 2 +# error "The logic in the functions below only works with two segments" +#endif + +static void wait_for_other_safe_points(void) +{ + long remote_num = 1 - STM_SEGMENT->segment_num; + while (get_priv_segment(remote_num)->safe_point == SP_RUNNING) { + cond_wait(); + } +} + +static void detect_write_read_conflicts(void) { long remote_num = 1 - STM_SEGMENT->segment_num; char *remote_base = get_segment_base(remote_num); uint8_t remote_version = get_segment(remote_num)->transaction_read_version; -#if NB_SEGMENTS != 2 -# error "This logic only works with two segments" -#endif + switch (get_priv_segment(remote_num)->transaction_state) { + case TS_NONE: + case TS_MUST_ABORT: + return; /* no need to do any check */ + } LIST_FOREACH_R( STM_PSEGMENT->modified_objects, @@ -136,11 +150,13 @@ ({ if (was_read_remote(remote_base, item, remote_version)) { /* A write-read conflict! */ - contention_management(remote_num); - return true; + contention_management(remote_num, false); + + /* If we reach this point, it means we aborted the other + thread. We're done here. */ + return; } })); - return false; } static void push_modified_to_other_segments(void) @@ -148,17 +164,18 @@ long remote_num = 1 - STM_SEGMENT->segment_num; char *local_base = STM_SEGMENT->segment_base; char *remote_base = get_segment_base(remote_num); - -#if NB_SEGMENTS != 2 -# error "This logic only works with two segments" -#endif + bool remote_active = + (get_priv_segment(remote_num)->transaction_state == TS_REGULAR || + get_priv_segment(remote_num)->transaction_state == TS_INEVITABLE); LIST_FOREACH_R( STM_PSEGMENT->modified_objects, object_t * /*item*/, ({ - assert(!was_read_remote(remote_base, item, + if (remote_active) { + assert(!was_read_remote(remote_base, item, get_segment(remote_num)->transaction_read_version)); + } /* clear the write-lock */ uintptr_t lock_idx = (((uintptr_t)item) >> 4) - READMARKER_START; @@ -176,8 +193,6 @@ void stm_commit_transaction(void) { mutex_lock(); - - restart: assert(STM_PSEGMENT->safe_point = SP_RUNNING); switch (STM_PSEGMENT->transaction_state) { @@ -193,9 +208,11 @@ assert(!"commit: bad transaction_state"); } + /* wait until the other thread is at a safe-point */ + wait_for_other_safe_points(); + /* detect conflicts */ - if (detect_write_read_conflicts()) - goto restart; + detect_write_read_conflicts(); /* cannot abort any more from here */ assert(STM_PSEGMENT->transaction_state != TS_MUST_ABORT); @@ -223,9 +240,6 @@ static void abort_with_mutex(void) { - stm_thread_local_t *tl = STM_SEGMENT->running_thread; - stm_jmpbuf_t *jmpbuf_ptr = STM_SEGMENT->jmpbuf_ptr; - switch (STM_PSEGMENT->transaction_state) { case TS_REGULAR: case TS_MUST_ABORT: @@ -236,6 +250,8 @@ assert(!"abort: bad transaction_state"); } + stm_jmpbuf_t *jmpbuf_ptr = STM_SEGMENT->jmpbuf_ptr; + stm_thread_local_t *tl = STM_SEGMENT->running_thread; release_thread_segment(tl); /* includes the cond_broadcast(); */ STM_PSEGMENT->safe_point = SP_NO_TRANSACTION; STM_PSEGMENT->transaction_state = TS_NONE; diff --git a/c7/stm/core.h b/c7/stm/core.h --- a/c7/stm/core.h +++ b/c7/stm/core.h @@ -109,3 +109,4 @@ } static void teardown_core(void); +static void abort_with_mutex(void) __attribute__((noreturn)); diff --git a/c7/stm/sync.c b/c7/stm/sync.c --- a/c7/stm/sync.c +++ b/c7/stm/sync.c @@ -80,11 +80,19 @@ static inline void cond_wait(void) { +#ifdef STM_NO_COND_WAIT + fprintf(stderr, "*** cond_wait called!"); + abort(); +#endif + if (UNLIKELY(pthread_cond_wait(&sync_ctl.global_cond, &sync_ctl.global_mutex) != 0)) { perror("pthread_cond_wait"); abort(); } + + if (STM_PSEGMENT->transaction_state == TS_MUST_ABORT) + abort_with_mutex(); } static inline void cond_broadcast(void) @@ -166,12 +174,19 @@ assert(STM_SEGMENT->running_thread == tl); } -void _stm_start_safe_point(int flags) +#if STM_TESTS +void _stm_start_safe_point(void) { - //... + assert(STM_PSEGMENT->safe_point == SP_RUNNING); + STM_PSEGMENT->safe_point = SP_SAFE_POINT_CAN_COLLECT; } -void _stm_stop_safe_point(int flags) +void _stm_stop_safe_point(void) { - //... + assert(STM_PSEGMENT->safe_point == SP_SAFE_POINT_CAN_COLLECT); + STM_PSEGMENT->safe_point = SP_RUNNING; + + if (STM_PSEGMENT->transaction_state == TS_MUST_ABORT) + stm_abort_transaction(); } +#endif diff --git a/c7/stmgc.h b/c7/stmgc.h --- a/c7/stmgc.h +++ b/c7/stmgc.h @@ -81,8 +81,6 @@ stm_char *_stm_allocate_slowpath(ssize_t); void _stm_become_inevitable(char*); void _stm_start_transaction(stm_thread_local_t *, stm_jmpbuf_t *); -void _stm_start_safe_point(int flags); -void _stm_stop_safe_point(int flags); #ifdef STM_TESTS bool _stm_was_read(object_t *obj); @@ -94,6 +92,8 @@ void _stm_test_switch(stm_thread_local_t *tl); object_t *_stm_allocate_old(ssize_t size_rounded_up); void _stm_large_dump(void); +void _stm_start_safe_point(void); +void _stm_stop_safe_point(void); #endif #define _STM_GCFLAG_WRITE_BARRIER_CALLED 0x80 diff --git a/c7/test/support.py b/c7/test/support.py --- a/c7/test/support.py +++ b/c7/test/support.py @@ -66,12 +66,8 @@ void _set_type_id(object_t *obj, uint32_t h); uint32_t _get_type_id(object_t *obj); -#define LOCK_COLLECT ... -#define LOCK_EXCLUSIVE ... -#define THREAD_YIELD ... - -void _stm_start_safe_point(int); -bool _check_stop_safe_point(int); +void _stm_start_safe_point(void); +bool _check_stop_safe_point(void); """) @@ -138,12 +134,6 @@ typedef TLPREFIX struct myobj_s myobj_t; #define SIZEOF_MYOBJ sizeof(struct myobj_s) -enum { - LOCK_COLLECT = 1, - LOCK_EXCLUSIVE = 2, - THREAD_YIELD = 4, -}; - uint8_t _stm_get_flags(object_t *obj) { return obj->stm_flags; @@ -195,13 +185,13 @@ } #endif -bool _check_stop_safe_point(int flags) { +bool _check_stop_safe_point(void) { stm_jmpbuf_t here; stm_segment_info_t *segment = STM_SEGMENT; if (__builtin_setjmp(here) == 0) { // returned directly assert(segment->jmpbuf_ptr == (stm_jmpbuf_t *)-1); segment->jmpbuf_ptr = &here; - _stm_stop_safe_point(flags); + _stm_stop_safe_point(); segment->jmpbuf_ptr = (stm_jmpbuf_t *)-1; return 0; } @@ -287,7 +277,7 @@ } ''', sources=source_files, - define_macros=[('STM_TESTS', '1')], + define_macros=[('STM_TESTS', '1'), ('STM_NO_COND_WAIT', '1')], undef_macros=['NDEBUG'], include_dirs=[parent_dir], extra_compile_args=['-g', '-O0', '-Werror'], @@ -369,10 +359,10 @@ def stm_start_safe_point(): - lib._stm_start_safe_point(lib.LOCK_COLLECT) + lib._stm_start_safe_point() def stm_stop_safe_point(): - if lib._check_stop_safe_point(lib.LOCK_COLLECT): + if lib._check_stop_safe_point(): raise Conflict() def stm_become_inevitable(): diff --git a/c7/test/test_basic.py b/c7/test/test_basic.py --- a/c7/test/test_basic.py +++ b/c7/test/test_basic.py @@ -96,7 +96,7 @@ self.commit_transaction() # py.test.raises(Conflict, self.switch, 0) # detects rw conflict - + def test_commit_fresh_objects(self): self.start_transaction() lp = stm_allocate(16) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit