Author: Armin Rigo <ar...@tunes.org> Branch: stmgc-c4 Changeset: r66825:42b90135f84b Date: 2013-09-06 22:30 +0200 http://bitbucket.org/pypy/pypy/changeset/42b90135f84b/
Log: merge heads diff --git a/pypy/module/__pypy__/interp_signal.py b/pypy/module/__pypy__/interp_signal.py --- a/pypy/module/__pypy__/interp_signal.py +++ b/pypy/module/__pypy__/interp_signal.py @@ -1,6 +1,9 @@ +from rpython.rlib import jit +@jit.dont_look_inside def signals_enter(space): space.threadlocals.enable_signals(space) +@jit.dont_look_inside def signals_exit(space, w_ignored1=None, w_ignored2=None, w_ignored3=None): space.threadlocals.disable_signals(space) diff --git a/pypy/module/thread/stm.py b/pypy/module/thread/stm.py --- a/pypy/module/thread/stm.py +++ b/pypy/module/thread/stm.py @@ -28,6 +28,7 @@ if not we_are_translated() and not hasattr(ec, '_thread_local_dicts'): initialize_execution_context(ec) +@jit.dont_look_inside # XXX: handle abort_info_push in JIT def enter_frame(ec, frame): """Called from ExecutionContext.enter().""" if frame.hide(): diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py --- a/rpython/rlib/rstm.py +++ b/rpython/rlib/rstm.py @@ -58,7 +58,6 @@ def is_atomic(): return llop.stm_get_atomic(lltype.Signed) -@dont_look_inside def abort_info_push(instance, fieldnames): "Special-cased below." diff --git a/rpython/translator/stm/src_stm/et.c b/rpython/translator/stm/src_stm/et.c --- a/rpython/translator/stm/src_stm/et.c +++ b/rpython/translator/stm/src_stm/et.c @@ -25,7 +25,7 @@ } cur += sprintf(cur, "tid=%ld", stm_get_tid(obj)); cur += sprintf(cur, " : rev=%lx : orig=%lx", - obj->h_revision, obj->h_original); + (long)obj->h_revision, (long)obj->h_original); return tmp_buf; } @@ -951,8 +951,8 @@ d->longest_abort_info_time = 0; /* out of memory! */ else { - if (stm_decode_abort_info(d, elapsed_time, - num, d->longest_abort_info) != size) + if (stm_decode_abort_info(d, elapsed_time, num, + (struct tx_abort_info *)d->longest_abort_info) != size) stm_fatalerror("during stm abort: object mutated unexpectedly\n"); d->longest_abort_info_time = elapsed_time; diff --git a/rpython/translator/stm/src_stm/extra.c b/rpython/translator/stm/src_stm/extra.c --- a/rpython/translator/stm/src_stm/extra.c +++ b/rpython/translator/stm/src_stm/extra.c @@ -236,13 +236,75 @@ } size_t stm_decode_abort_info(struct tx_descriptor *d, long long elapsed_time, - int abort_reason, char *output) + int abort_reason, struct tx_abort_info *output) { - /* re-encodes the abort info as a single string. + /* Re-encodes the abort info as a single tx_abort_info structure. + This struct tx_abort_info is not visible to the outside, and used + only as an intermediate format that is fast to generate and without + requiring stm_read_barrier(). + */ + if (output != NULL) { + output->signature_packed = 127; + output->elapsed_time = elapsed_time; + output->abort_reason = abort_reason; + output->active = d->active; + output->atomic = d->atomic; + output->count_reads = d->count_reads; + output->reads_size_limit_nonatomic = d->reads_size_limit_nonatomic; + } + + long num_words = 0; +#define WRITE_WORD(word) { \ + if (output) output->words[num_words] = (word); \ + num_words++; \ + } + + long i; + for (i=0; i<d->abortinfo.size; i+=2) { + char *object = (char*)stm_repeat_read_barrier(d->abortinfo.items[i+0]); + long *fieldoffsets = (long*)d->abortinfo.items[i+1]; + long kind, offset; + while (*fieldoffsets != 0) { + kind = *fieldoffsets++; + WRITE_WORD(kind); + if (kind < 0) { + /* -1 is start of sublist; -2 is end of sublist */ + continue; + } + offset = *fieldoffsets++; + switch(kind) { + case 1: /* signed */ + case 2: /* unsigned */ + WRITE_WORD(*(long *)(object + offset)); + break; + case 3: /* a string of bytes from the target object */ + WRITE_WORD((revision_t)*(char **)(object + offset)); + offset = *fieldoffsets++; /* offset of len in the string */ + WRITE_WORD(offset); + break; + default: + stm_fatalerror("corrupted abort log\n"); + } + } + } + WRITE_WORD(0); +#undef WRITE_WORD + return sizeof(struct tx_abort_info) + (num_words - 1) * sizeof(revision_t); +} + +static size_t unpack_abort_info(struct tx_descriptor *d, + struct tx_abort_info *ai, + char *output) +{ + /* Lazily decodes a struct tx_abort_info into a single plain string. For convenience (no escaping needed, no limit on integer - sizes, etc.) we follow the bittorrent format. */ + sizes, etc.) we follow the bittorrent format. This makes the + format a bit more flexible for future changes. The struct + tx_abort_info is still needed as an intermediate step, because + the string parameters may not be readable during an abort + (they may be stubs). + */ size_t totalsize = 0; - long i; char buffer[32]; size_t res_size; #define WRITE(c) { totalsize++; if (output) *output++=(c); } @@ -253,75 +315,74 @@ } WRITE('l'); WRITE('l'); - res_size = sprintf(buffer, "i%llde", (long long)elapsed_time); + res_size = sprintf(buffer, "i%llde", (long long)ai->elapsed_time); WRITE_BUF(buffer, res_size); - res_size = sprintf(buffer, "i%de", (int)abort_reason); + res_size = sprintf(buffer, "i%de", (int)ai->abort_reason); WRITE_BUF(buffer, res_size); res_size = sprintf(buffer, "i%lde", (long)d->public_descriptor_index); WRITE_BUF(buffer, res_size); - res_size = sprintf(buffer, "i%lde", (long)d->atomic); + res_size = sprintf(buffer, "i%lde", (long)ai->atomic); WRITE_BUF(buffer, res_size); - res_size = sprintf(buffer, "i%de", (int)d->active); + res_size = sprintf(buffer, "i%de", (int)ai->active); WRITE_BUF(buffer, res_size); - res_size = sprintf(buffer, "i%lue", (unsigned long)d->count_reads); + res_size = sprintf(buffer, "i%lue", (unsigned long)ai->count_reads); WRITE_BUF(buffer, res_size); res_size = sprintf(buffer, "i%lue", - (unsigned long)d->reads_size_limit_nonatomic); + (unsigned long)ai->reads_size_limit_nonatomic); WRITE_BUF(buffer, res_size); WRITE('e'); - for (i=0; i<d->abortinfo.size; i+=2) { - char *object = (char*)stm_repeat_read_barrier(d->abortinfo.items[i+0]); - long *fieldoffsets = (long*)d->abortinfo.items[i+1]; - long kind, offset; - size_t rps_size; + + revision_t *src = ai->words; + while (*src != 0) { + long signed_value; + unsigned long unsigned_value; char *rps; + long offset, rps_size; - while (1) { - kind = *fieldoffsets++; - if (kind <= 0) { - if (kind == -2) { - WRITE('l'); /* '[', start of sublist */ - continue; - } - if (kind == -1) { - WRITE('e'); /* ']', end of sublist */ - continue; - } - break; /* 0, terminator */ + switch (*src++) { + + case -2: + WRITE('l'); /* '[', start of sublist */ + break; + + case -1: + WRITE('e'); /* ']', end of sublist */ + break; + + case 1: /* signed */ + signed_value = (long)(*src++); + res_size = sprintf(buffer, "i%lde", signed_value); + WRITE_BUF(buffer, res_size); + break; + + case 2: /* unsigned */ + unsigned_value = (unsigned long)(*src++); + res_size = sprintf(buffer, "i%lue", unsigned_value); + WRITE_BUF(buffer, res_size); + break; + + case 3: /* a string of bytes from the target object */ + rps = (char *)(*src++); + offset = *src++; + if (rps) { + rps = (char *)stm_read_barrier((gcptr)rps); + /* xxx a bit ad-hoc: it's a string whose length is a + * long at 'rps_size'; the string data follows + * immediately the length */ + rps_size = *(long *)(rps + offset); + assert(rps_size >= 0); + res_size = sprintf(buffer, "%ld:", rps_size); + WRITE_BUF(buffer, res_size); + WRITE_BUF(rps + offset + sizeof(long), rps_size); } - offset = *fieldoffsets++; - switch(kind) { - case 1: /* signed */ - res_size = sprintf(buffer, "i%lde", - *(long*)(object + offset)); - WRITE_BUF(buffer, res_size); - break; - case 2: /* unsigned */ - res_size = sprintf(buffer, "i%lue", - *(unsigned long*)(object + offset)); - WRITE_BUF(buffer, res_size); - break; - case 3: /* a string of bytes from the target object */ - rps = *(char **)(object + offset); - offset = *fieldoffsets++; - /* XXX think of a different hack: this one doesn't really - work if we see stubs! */ - if (rps && !(((gcptr)rps)->h_tid & GCFLAG_STUB)) { - /* xxx a bit ad-hoc: it's a string whose length is a - * long at 'offset', following immediately the offset */ - rps_size = *(long *)(rps + offset); - assert(rps_size >= 0); - res_size = sprintf(buffer, "%zu:", rps_size); - WRITE_BUF(buffer, res_size); - WRITE_BUF(rps + offset + sizeof(long), rps_size); - } - else { - WRITE_BUF("0:", 2); - } - break; - default: - stm_fatalerror("corrupted abort log\n"); + else { + /* write NULL as an empty string, good enough for now */ + WRITE_BUF("0:", 2); } + break; + + default: + stm_fatalerror("corrupted abort log\n"); } } WRITE('e'); @@ -336,6 +397,53 @@ struct tx_descriptor *d = thread_descriptor; if (d->longest_abort_info_time <= 0) return NULL; + + struct tx_abort_info *ai = (struct tx_abort_info *)d->longest_abort_info; + assert(ai->signature_packed == 127); + + stm_become_inevitable("stm_inspect_abort_info"); + + size_t size = unpack_abort_info(d, ai, NULL); + char *text = malloc(size); + if (text == NULL) + return NULL; /* out of memory */ + if (unpack_abort_info(d, ai, text) != size) + stm_fatalerror("stm_inspect_abort_info: " + "object mutated unexpectedly\n"); + free(ai); + d->longest_abort_info = text; d->longest_abort_info_time = 0; return d->longest_abort_info; } + +void stm_visit_abort_info(struct tx_descriptor *d, void (*visit)(gcptr *)) +{ + long i, size = d->abortinfo.size; + gcptr *items = d->abortinfo.items; + for (i = 0; i < size; i += 2) { + visit(&items[i]); + /* items[i+1] is not a gc ptr */ + } + + struct tx_abort_info *ai = (struct tx_abort_info *)d->longest_abort_info; + if (ai != NULL && ai->signature_packed == 127) { + revision_t *src = ai->words; + while (*src != 0) { + gcptr *rpps; + + switch (*src++) { + + case 1: /* signed */ + case 2: /* unsigned */ + src++; /* ignore the value */ + break; + + case 3: + rpps = (gcptr *)(src++); + src++; /* ignore the offset */ + visit(rpps); /* visit() the string object */ + break; + } + } + } +} diff --git a/rpython/translator/stm/src_stm/extra.h b/rpython/translator/stm/src_stm/extra.h --- a/rpython/translator/stm/src_stm/extra.h +++ b/rpython/translator/stm/src_stm/extra.h @@ -3,8 +3,20 @@ #define _SRCSTM_EXTRA_H +struct tx_abort_info { + char signature_packed; /* 127 when the abort_info is in this format */ + long long elapsed_time; + int abort_reason; + int active; + long atomic; + unsigned long count_reads; + unsigned long reads_size_limit_nonatomic; + revision_t words[1]; /* the 'words' list is a bytecode-like format */ +}; + void stm_copy_to_old_id_copy(gcptr obj, gcptr id); size_t stm_decode_abort_info(struct tx_descriptor *d, long long elapsed_time, - int abort_reason, char *output); + int abort_reason, struct tx_abort_info *output); +void stm_visit_abort_info(struct tx_descriptor *d, void (*visit)(gcptr *)); #endif diff --git a/rpython/translator/stm/src_stm/gcpage.c b/rpython/translator/stm/src_stm/gcpage.c --- a/rpython/translator/stm/src_stm/gcpage.c +++ b/rpython/translator/stm/src_stm/gcpage.c @@ -563,12 +563,7 @@ visit_take_protected(&d->old_thread_local_obj); /* the abortinfo objects */ - long i, size = d->abortinfo.size; - gcptr *items = d->abortinfo.items; - for (i = 0; i < size; i += 2) { - visit_take_protected(&items[i]); - /* items[i+1] is not a gc ptr */ - } + stm_visit_abort_info(d, &visit_take_protected); /* the current transaction's private copies of public objects */ wlog_t *item; @@ -601,8 +596,8 @@ } G2L_LOOP_END; /* reinsert to real pub_to_priv */ - size = new_public_to_private.size; - items = new_public_to_private.items; + long i, size = new_public_to_private.size; + gcptr *items = new_public_to_private.items; for (i = 0; i < size; i += 2) { g2l_insert(&d->public_to_private, items[i], items[i + 1]); } diff --git a/rpython/translator/stm/src_stm/nursery.c b/rpython/translator/stm/src_stm/nursery.c --- a/rpython/translator/stm/src_stm/nursery.c +++ b/rpython/translator/stm/src_stm/nursery.c @@ -456,12 +456,7 @@ visit_if_young(d->thread_local_obj_ref); visit_if_young(&d->old_thread_local_obj); - long i, size = d->abortinfo.size; - gcptr *items = d->abortinfo.items; - for (i = 0; i < size; i += 2) { - visit_if_young(&items[i]); - /* items[i+1] is not a gc ptr */ - } + stm_visit_abort_info(d, &visit_if_young); } static void minor_collect(struct tx_descriptor *d) diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision --- a/rpython/translator/stm/src_stm/revision +++ b/rpython/translator/stm/src_stm/revision @@ -1,1 +1,1 @@ -8b92101281e9 +24b6be3aaa67 diff --git a/rpython/translator/stm/src_stm/stmgc.h b/rpython/translator/stm/src_stm/stmgc.h --- a/rpython/translator/stm/src_stm/stmgc.h +++ b/rpython/translator/stm/src_stm/stmgc.h @@ -155,7 +155,7 @@ stm_inspect_abort_info(). (XXX details not documented yet) */ void stm_abort_info_push(gcptr obj, long fieldoffsets[]); void stm_abort_info_pop(long count); -char *stm_inspect_abort_info(void); +char *stm_inspect_abort_info(void); /* turns inevitable */ /* mostly for debugging support */ void stm_abort_and_retry(void); _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit