[pypy-commit] stmgc default: add inevitable transactions
Raemi
noreply at buildbot.pypy.org
Mon Sep 8 11:20:39 CEST 2014
Author: Remi Meier <remi.meier at 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()
More information about the pypy-commit
mailing list