Author: Remi Meier <remi.me...@inf.ethz.ch> Branch: Changeset: r1364:5b5ed3773ccf Date: 2014-09-08 11:22 +0200 http://bitbucket.org/pypy/stmgc/changeset/5b5ed3773ccf/
Log: add inevitable transactions diff --git a/c8/stm/core.c b/c8/stm/core.c --- a/c8/stm/core.c +++ b/c8/stm/core.c @@ -110,13 +110,17 @@ void _dbg_print_commit_log() { - volatile struct stm_commit_log_entry_s *cl = (volatile struct stm_commit_log_entry_s *) - &commit_log_root; + volatile struct stm_commit_log_entry_s *cl; + cl = (volatile struct stm_commit_log_entry_s *)&commit_log_root; fprintf(stderr, "root (%p, %d)\n", cl->next, cl->segment_num); while ((cl = cl->next)) { + if ((uintptr_t)cl == -1) { + fprintf(stderr, "INEVITABLE\n"); + return; + } size_t i = 0; - fprintf(stderr, "elem (%p, %d)\n", cl->next, cl->segment_num); + fprintf(stderr, " elem (%p, %d)\n", cl->next, cl->segment_num); object_t *obj; while ((obj = cl->written[i])) { fprintf(stderr, "-> %p\n", obj); @@ -176,13 +180,21 @@ most current one and apply all changes done by other transactions. Abort if we read one of the committed objs. */ - volatile struct stm_commit_log_entry_s *cl = (volatile struct stm_commit_log_entry_s *) + volatile struct stm_commit_log_entry_s *cl, *prev_cl; + cl = prev_cl = (volatile struct stm_commit_log_entry_s *) STM_PSEGMENT->last_commit_log_entry; - acquire_privatization_lock(STM_SEGMENT->segment_num); bool needs_abort = false; /* Don't check 'cl'. This entry is already checked */ while ((cl = cl->next)) { + if ((uintptr_t)cl == -1) { + /* there is an inevitable transaction running */ + cl = prev_cl; + usleep(1); /* XXX */ + continue; + } + prev_cl = cl; + OPT_ASSERT(cl->segment_num >= 0 && cl->segment_num < NB_SEGMENTS); object_t *obj; @@ -200,7 +212,6 @@ /* last fully validated entry */ STM_PSEGMENT->last_commit_log_entry = (struct stm_commit_log_entry_s *)cl; } - release_privatization_lock(STM_SEGMENT->segment_num); if (needs_abort) { free(free_if_abort); @@ -241,6 +252,16 @@ volatile struct stm_commit_log_entry_s **to; new = _create_commit_log_entry(); + if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) { + OPT_ASSERT((uintptr_t)STM_PSEGMENT->last_commit_log_entry->next == -1); + + to = &(STM_PSEGMENT->last_commit_log_entry->next); + bool yes = __sync_bool_compare_and_swap(to, -1, new); + OPT_ASSERT(yes); + return; + } + + /* regular transaction: */ do { stm_validate(new); @@ -249,6 +270,20 @@ } while (!__sync_bool_compare_and_swap(to, NULL, new)); } +static void _validate_and_turn_inevitable() +{ + struct stm_commit_log_entry_s *new; + volatile struct stm_commit_log_entry_s **to; + + new = (struct stm_commit_log_entry_s*)-1; + do { + stm_validate(NULL); + + /* try attaching to commit log: */ + to = &(STM_PSEGMENT->last_commit_log_entry->next); + } while (!__sync_bool_compare_and_swap(to, NULL, new)); +} + /* ############# STM ############# */ void _privatize_and_protect_other_segments(object_t *obj) @@ -382,7 +417,7 @@ } -static void _stm_start_transaction(stm_thread_local_t *tl, bool inevitable) +static void _stm_start_transaction(stm_thread_local_t *tl) { assert(!_stm_in_transaction(tl)); @@ -392,6 +427,8 @@ goto retry; /* GS invalid before this point! */ + assert(STM_PSEGMENT->transaction_state == TS_NONE); + STM_PSEGMENT->transaction_state = TS_REGULAR; #ifndef NDEBUG STM_PSEGMENT->running_pthread = pthread_self(); #endif @@ -421,10 +458,28 @@ #else long repeat_count = stm_rewind_jmp_setjmp(tl); #endif - _stm_start_transaction(tl, false); + _stm_start_transaction(tl); return repeat_count; } +void stm_start_inevitable_transaction(stm_thread_local_t *tl) +{ + s_mutex_lock(); + _stm_start_transaction(tl); + _stm_become_inevitable("stm_start_inevitable_transaction"); +} + +#ifdef STM_NO_AUTOMATIC_SETJMP +void _test_run_abort(stm_thread_local_t *tl) __attribute__((noreturn)); +int stm_is_inevitable(void) +{ + switch (STM_PSEGMENT->transaction_state) { + case TS_REGULAR: return 0; + case TS_INEVITABLE: return 1; + default: abort(); + } +} +#endif /************************************************************/ @@ -432,6 +487,7 @@ { stm_thread_local_t *tl = STM_SEGMENT->running_thread; + STM_PSEGMENT->transaction_state = TS_NONE; list_clear(STM_PSEGMENT->objects_pointing_to_nursery); release_thread_segment(tl); @@ -443,6 +499,7 @@ assert(!_has_mutex()); assert(STM_PSEGMENT->running_pthread == pthread_self()); + dprintf(("stm_commit_transaction()\n")); minor_collection(1); _validate_and_add_to_commit_log(); @@ -469,7 +526,6 @@ assert(STM_SEGMENT->nursery_end == NURSERY_END); stm_rewind_jmp_forget(STM_SEGMENT->running_thread); - /* done */ _finish_transaction(); /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */ @@ -519,6 +575,16 @@ #undef STM_SEGMENT struct stm_priv_segment_info_s *pseg = get_priv_segment(segment_num); + switch (pseg->transaction_state) { + case TS_REGULAR: + break; + case TS_INEVITABLE: + stm_fatalerror("abort: transaction_state == TS_INEVITABLE"); + default: + stm_fatalerror("abort: bad transaction_state == %d", + (int)pseg->transaction_state); + } + throw_away_nursery(pseg); reset_modified_from_backup_copies(segment_num); @@ -582,3 +648,22 @@ stm_rewind_jmp_longjmp(tl); #endif } + + +void _stm_become_inevitable(const char *msg) +{ + s_mutex_lock(); + + if (STM_PSEGMENT->transaction_state == TS_REGULAR) { + dprintf(("become_inevitable: %s\n", msg)); + + _validate_and_turn_inevitable(); + STM_PSEGMENT->transaction_state = TS_INEVITABLE; + stm_rewind_jmp_forget(STM_SEGMENT->running_thread); + } + else { + assert(STM_PSEGMENT->transaction_state == TS_INEVITABLE); + } + + s_mutex_unlock(); +} diff --git a/c8/stm/core.h b/c8/stm/core.h --- a/c8/stm/core.h +++ b/c8/stm/core.h @@ -53,6 +53,8 @@ struct list_s *objects_pointing_to_nursery; uint8_t privatization_lock; + uint8_t transaction_state; + struct stm_commit_log_entry_s *last_commit_log_entry; struct stm_shadowentry_s *shadowstack_at_start_of_transaction; @@ -63,6 +65,12 @@ #endif }; +enum /* transaction_state */ { + TS_NONE=0, + TS_REGULAR, + TS_INEVITABLE, +}; + /* Commit Log things */ struct stm_commit_log_entry_s { volatile struct stm_commit_log_entry_s *next; diff --git a/c8/stmgc.h b/c8/stmgc.h --- a/c8/stmgc.h +++ b/c8/stmgc.h @@ -69,6 +69,7 @@ void _stm_write_slowpath(object_t *); object_t *_stm_allocate_slowpath(ssize_t); +void _stm_become_inevitable(const char*); object_t *_stm_allocate_old(ssize_t size_rounded_up); char *_stm_real_address(object_t *o); @@ -186,10 +187,27 @@ long stm_start_transaction(stm_thread_local_t *tl); +void stm_start_inevitable_transaction(stm_thread_local_t *tl); + void stm_commit_transaction(void); void stm_abort_transaction(void) __attribute__((noreturn)); +#ifdef STM_NO_AUTOMATIC_SETJMP +int stm_is_inevitable(void); +#else +static inline int stm_is_inevitable(void) { + return !rewind_jmp_armed(&STM_SEGMENT->running_thread->rjthread); +} +#endif +static inline void stm_become_inevitable(stm_thread_local_t *tl, + const char* msg) { + assert(STM_SEGMENT->running_thread == tl); + if (!stm_is_inevitable()) + _stm_become_inevitable(msg); +} + + /* ==================== END ==================== */ #endif diff --git a/c8/test/support.py b/c8/test/support.py --- a/c8/test/support.py +++ b/c8/test/support.py @@ -57,6 +57,8 @@ long stm_start_transaction(stm_thread_local_t *tl); bool _check_commit_transaction(void); bool _check_abort_transaction(void); +bool _check_become_inevitable(stm_thread_local_t *tl); +int stm_is_inevitable(void); void _set_type_id(object_t *obj, uint32_t h); uint32_t _get_type_id(object_t *obj); @@ -134,6 +136,10 @@ CHECKED(stm_abort_transaction()); } +bool _check_become_inevitable(stm_thread_local_t *tl) { + CHECKED(stm_become_inevitable(tl, "TEST")); +} + bool _check_stm_validate(void) { CHECKED(stm_validate(NULL)); } @@ -413,12 +419,18 @@ def teardown_method(self, meth): lib.stmcb_expand_marker = ffi.NULL lib.stmcb_debug_print = ffi.NULL + tl = self.tls[self.current_thread] + if lib._stm_in_transaction(tl) and lib.stm_is_inevitable(): + self.commit_transaction() # must succeed! # for n, tl in enumerate(self.tls): if lib._stm_in_transaction(tl): if self.current_thread != n: self.switch(n) - self.abort_transaction() + if lib.stm_is_inevitable(): + self.commit_transaction() # must succeed! + else: + self.abort_transaction() # for tl in self.tls: lib.stm_unregister_thread_local(tl) @@ -504,3 +516,8 @@ def set_thread_local_obj(self, newobj): tl = self.tls[self.current_thread] tl.thread_local_obj = newobj + + def become_inevitable(self): + tl = self.tls[self.current_thread] + if lib._check_become_inevitable(tl): + raise Conflict() _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit