1. ModCloth
  2. Untitled project
  3. pypy

Commits

Armin Rigo  committed 5813171

Switch to encoding/decoding following the bittorrent file format.
It's a convenient format that requires minimal effort and no
escaping pain.

  • Participants
  • Parent commits 6374958
  • Branches stm-thread-2

Comments (0)

Files changed (8)

File pypy/interpreter/executioncontext.py

View file
  • Ignore whitespace
         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)
 
         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):

File pypy/module/__pypy__/__init__.py

View file
  • Ignore whitespace
         '_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',
     }
 
 

File pypy/module/__pypy__/interp_atomic.py

View file
  • Ignore whitespace
 from pypy.interpreter.error import OperationError
 from pypy.module.thread.error import wrap_thread_error
+from rpython.rtyper.lltypesystem import rffi
 
 
 
             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

File pypy/module/__pypy__/test/test_atomic.py

View file
  • Ignore whitespace
 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):

File pypy/module/thread/stm.py

View file
  • Ignore whitespace
 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
     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):
 

File rpython/rlib/rstm.py

View file
  • Ignore whitespace
 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()
 
     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])
 
 # ____________________________________________________________

File rpython/translator/stm/src_stm/rpyintf.c

View file
  • Ignore whitespace
 
 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;

File rpython/translator/stm/test/test_ztranslated.py

View file
  • Ignore whitespace
 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
 
         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
             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