Author: Armin Rigo <[email protected]>
Branch: stm-thread-2
Changeset: r61588:5813171b4407
Date: 2013-02-22 10:12 +0100
http://bitbucket.org/pypy/pypy/changeset/5813171b4407/
Log: Switch to encoding/decoding following the bittorrent file format.
It's a convenient format that requires minimal effort and no
escaping pain.
diff --git a/pypy/interpreter/executioncontext.py
b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -60,6 +60,9 @@
return frame
def enter(self, frame):
+ if self.space.config.translation.stm:
+ from pypy.module.thread.stm import enter_frame
+ enter_frame(self, frame)
frame.f_backref = self.topframeref
self.topframeref = jit.virtual_ref(frame)
@@ -84,6 +87,10 @@
if self.w_tracefunc is not None and not frame.hide():
self.space.frame_trace_action.fire()
+ if self.space.config.translation.stm:
+ from pypy.module.thread.stm import leave_frame
+ leave_frame(self, frame)
+
# ________________________________________________________________
def c_call_trace(self, frame, w_func, args=None):
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -39,6 +39,8 @@
'_atomic_enter': 'interp_atomic.atomic_enter',
'_exclusive_atomic_enter': 'interp_atomic.exclusive_atomic_enter',
'_atomic_exit': 'interp_atomic.atomic_exit',
+ '_raw_last_abort_info': 'interp_atomic.raw_last_abort_info',
+ 'last_abort_info': 'interp_atomic.last_abort_info',
}
diff --git a/pypy/module/__pypy__/interp_atomic.py
b/pypy/module/__pypy__/interp_atomic.py
--- a/pypy/module/__pypy__/interp_atomic.py
+++ b/pypy/module/__pypy__/interp_atomic.py
@@ -1,5 +1,6 @@
from pypy.interpreter.error import OperationError
from pypy.module.thread.error import wrap_thread_error
+from rpython.rtyper.lltypesystem import rffi
@@ -39,3 +40,53 @@
return
raise wrap_thread_error(space,
"atomic.__exit__(): more exits than enters")
+
+def raw_last_abort_info(space):
+ return space.wrap(rstm.inspect_abort_info())
+
+def last_abort_info(space):
+ p = rstm.inspect_abort_info()
+ if not p:
+ return space.w_None
+ assert p[0] == 'l'
+ w_obj, p = bdecode(space, p)
+ return w_obj
+
+def bdecode(space, p):
+ return decoder[p[0]](space, p)
+
+def bdecodeint(space, p):
+ p = rffi.ptradd(p, 1)
+ n = 0
+ while p[n] != 'e':
+ n += 1
+ return (space.int(space.wrap(rffi.charpsize2str(p, n))),
+ rffi.ptradd(p, n + 1))
+
+def bdecodelist(space, p):
+ p = rffi.ptradd(p, 1)
+ w_list = space.newlist()
+ while p[0] != 'e':
+ w_obj, p = bdecode(space, p)
+ space.call_method(w_list, 'append', w_obj)
+ return (w_list, rffi.ptradd(p, 1))
+
+def bdecodestr(space, p):
+ length = 0
+ n = 0
+ while p[n] != ':':
+ c = p[n]
+ n += 1
+ assert '0' <= c <= '9'
+ length = length * 10 + (ord(c) - ord('0'))
+ n += 1
+ p = rffi.ptradd(p, n)
+ return (space.wrap(rffi.charpsize2str(p, length)),
+ rffi.ptradd(p, length))
+
+decoder = {'i': bdecodeint,
+ 'l': bdecodelist,
+ #'d': bdecodedict,
+ }
+for c in '0123456789':
+ decoder[c] = bdecodestr
diff --git a/pypy/module/__pypy__/test/test_atomic.py
b/pypy/module/__pypy__/test/test_atomic.py
--- a/pypy/module/__pypy__/test/test_atomic.py
+++ b/pypy/module/__pypy__/test/test_atomic.py
@@ -1,5 +1,37 @@
from __future__ import with_statement
from pypy.module.thread.test.support import GenericTestThread
+from pypy.module.__pypy__.interp_atomic import bdecode
+from rpython.rtyper.lltypesystem import rffi
+
+
+def test_bdecode():
+ class FakeSpace:
+ def wrap(self, x):
+ assert isinstance(x, str)
+ return x
+ def int(self, x):
+ assert isinstance(x, str)
+ return int(x)
+ def newlist(self):
+ return []
+ def call_method(self, w_obj, method, *args):
+ assert method == 'append'
+ w_obj.append(*args)
+
+ space = FakeSpace()
+
+ def bdec(s):
+ p = rffi.str2charp(s)
+ w_obj, q = bdecode(space, p)
+ assert q == rffi.ptradd(p, len(s))
+ rffi.free_charp(p)
+ return w_obj
+
+ assert bdec("i123e") == 123
+ assert bdec("i-123e") == -123
+ assert bdec('12:+"*-%&/()=?\x00') == '+"*-%&/()=?\x00'
+ assert bdec("li123eli456eee") == [123, [456]]
+ assert bdec("l5:abcdei2ee") == ["abcde", 2]
class AppTestAtomic(GenericTestThread):
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
@@ -17,6 +17,7 @@
ec_cache = rstm.ThreadLocalReference(ExecutionContext)
def initialize_execution_context(ec):
+ """Called from ExecutionContext.__init__()."""
ec._thread_local_dicts = rweakref.RWeakKeyDictionary(STMLocal, W_Root)
if ec.space.config.objspace.std.withmethodcache:
from pypy.objspace.std.typeobject import MethodCache
@@ -26,6 +27,16 @@
if not we_are_translated() and not hasattr(ec, '_thread_local_dicts'):
initialize_execution_context(ec)
+def enter_frame(ec, frame):
+ """Called from ExecutionContext.enter()."""
+ rstm.abort_info_push(frame.pycode, ('[', 'co_filename', 'co_name',
+ 'co_firstlineno', 'co_lnotab'))
+ rstm.abort_info_push(frame, ('last_instr', ']'))
+
+def leave_frame(ec, frame):
+ """Called from ExecutionContext.leave()."""
+ rstm.abort_info_pop(2)
+
class STMThreadLocals(BaseThreadLocals):
diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py
--- a/rpython/rlib/rstm.py
+++ b/rpython/rlib/rstm.py
@@ -39,12 +39,8 @@
def abort_info_pop(count):
stmgcintf.StmOperations.abort_info_pop(count)
-def inspect_abort_info():
- p = stmgcintf.StmOperations.inspect_abort_info()
- if p:
- return rffi.charp2str(p)
- else:
- return None
+def charp_inspect_abort_info():
+ return stmgcintf.StmOperations.inspect_abort_info()
def abort_and_retry():
stmgcintf.StmOperations.abort_and_retry()
@@ -134,30 +130,37 @@
def specialize_call(self, hop):
fieldnames = hop.args_s[1].const
- lst = [len(fieldnames)]
+ lst = []
v_instance = hop.inputarg(hop.args_r[0], arg=0)
STRUCT = v_instance.concretetype.TO
for fieldname in fieldnames:
+ if fieldname == '[':
+ lst.append(-2) # start of sublist
+ continue
+ if fieldname == ']':
+ lst.append(-1) # end of sublist
+ continue
fieldname = 'inst_' + fieldname
TYPE = getattr(STRUCT, fieldname) #xxx check also in parent structs
if TYPE == lltype.Signed:
- kind = 0
+ kind = 1
elif TYPE == lltype.Unsigned:
- kind = 1
+ kind = 2
elif TYPE == lltype.Ptr(rstr.STR):
- kind = 2
+ kind = 3
else:
raise NotImplementedError(
"abort_info_push(%s, %r): field of type %r"
% (STRUCT.__name__, fieldname, TYPE))
lst.append(kind)
lst.append(llmemory.offsetof(STRUCT, fieldname))
+ lst.append(0)
ARRAY = rffi.CArray(lltype.Signed)
array = lltype.malloc(ARRAY, len(lst), flavor='raw', immortal=True)
for i in range(len(lst)):
array[i] = lst[i]
+ c_array = hop.inputconst(lltype.Ptr(ARRAY), array)
hop.exception_cannot_occur()
- c_array = hop.inputconst(lltype.Ptr(ARRAY), array)
hop.genop('stm_abort_info_push', [v_instance, c_array])
# ____________________________________________________________
diff --git a/rpython/translator/stm/src_stm/rpyintf.c
b/rpython/translator/stm/src_stm/rpyintf.c
--- a/rpython/translator/stm/src_stm/rpyintf.c
+++ b/rpython/translator/stm/src_stm/rpyintf.c
@@ -211,45 +211,65 @@
size_t _stm_decode_abort_info(struct tx_descriptor *d, char *output)
{
+ /* re-encodes the abort info as a single string.
+ For convenience (no escaping needed, no limit on integer
+ sizes, etc.) we follow the bittorrent format. */
size_t totalsize = 0;
long i;
#define WRITE(c) { totalsize++; if (output) *output++=(c); }
+#define WRITE_BUF(p, sz) { totalsize += (sz); \
+ if (output) { \
+ memcpy(output, (p), (sz)); output += (sz); \
+ } \
+ }
+ WRITE('l');
for (i=0; i<d->abortinfo.size; i+=2) {
char *object = (char*)d->abortinfo.items[i+0];
long *fieldoffsets = (long*)d->abortinfo.items[i+1];
- long j;
- for (j=0; j<fieldoffsets[0]; j++) {
- long kind = fieldoffsets[1+2*j+0];
- long offset = fieldoffsets[1+2*j+1];
- char buffer[24];
- char *result = buffer;
- size_t res_size;
- RPyString *rps;
+ long kind, offset;
+ char buffer[32];
+ size_t res_size, rps_size;
+ RPyString *rps;
+
+ 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 */
+ }
+ offset = *fieldoffsets++;
switch(kind) {
- case 0: /* signed */
- res_size = sprintf(buffer, "%ld", *(long*)(object + offset));
+ case 1: /* signed */
+ res_size = sprintf(buffer, "i%lde",
+ *(long*)(object + offset));
+ WRITE_BUF(buffer, res_size);
break;
- case 1: /* unsigned */
- res_size = sprintf(buffer, "%lu",
+ case 2: /* unsigned */
+ res_size = sprintf(buffer, "i%lue",
*(unsigned long*)(object + offset));
+ WRITE_BUF(buffer, res_size);
break;
- case 2: /* pointer to STR */
+ case 3: /* pointer to STR */
rps = *(RPyString **)(object + offset);
- res_size = RPyString_Size(rps);
- result = _RPyString_AsString(rps);
+ rps_size = RPyString_Size(rps);
+ res_size = sprintf(buffer, "%zu:", rps_size);
+ WRITE_BUF(buffer, res_size);
+ WRITE_BUF(_RPyString_AsString(rps), rps_size);
break;
default:
fprintf(stderr, "Fatal RPython error: corrupted abort log\n");
abort();
}
- while (res_size > 0) {
- WRITE(*result);
- result++;
- res_size--;
- }
- WRITE('\n');
}
}
+ WRITE('e');
WRITE('\0'); /* final null character */
#undef WRITE
return totalsize;
diff --git a/rpython/translator/stm/test/test_ztranslated.py
b/rpython/translator/stm/test/test_ztranslated.py
--- a/rpython/translator/stm/test/test_ztranslated.py
+++ b/rpython/translator/stm/test/test_ztranslated.py
@@ -1,6 +1,6 @@
import py
from rpython.rlib import rstm, rgc
-from rpython.rtyper.lltypesystem import lltype, llmemory
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr
from rpython.translator.stm.test.support import NoGcCompiledSTMTests
@@ -138,11 +138,11 @@
def check(_, retry_counter):
globf.xy = 100 + retry_counter
- rstm.abort_info_push(globf, ('xy', 'yx'))
+ rstm.abort_info_push(globf, ('xy', '[', 'yx', ']'))
if retry_counter < 3:
rstm.abort_and_retry()
#
- print rstm.inspect_abort_info()
+ print rffi.charp2str(rstm.charp_inspect_abort_info())
#
rstm.abort_info_pop(2)
return 0
@@ -156,4 +156,4 @@
return 0
t, cbuilder = self.compile(main)
data = cbuilder.cmdexec('a b')
- assert '102\nhi there 3\n\n' in data
+ assert 'li102el10:hi there 3ee\n' in data
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit