[pypy-svn] r45890 - in pypy/branch/pypy-more-rtti-inprogress/module/thread: . test

fijal at codespeak.net fijal at codespeak.net
Mon Aug 20 21:34:58 CEST 2007


Author: fijal
Date: Mon Aug 20 21:34:58 2007
New Revision: 45890

Modified:
   pypy/branch/pypy-more-rtti-inprogress/module/thread/ll_thread.py
   pypy/branch/pypy-more-rtti-inprogress/module/thread/test/test_ll_thread.py
Log:
Move ll_thread from dist here. This includes mostly API-refactoring
for being more cpython thread-like on RPython level.


Modified: pypy/branch/pypy-more-rtti-inprogress/module/thread/ll_thread.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/module/thread/ll_thread.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/module/thread/ll_thread.py	Mon Aug 20 21:34:58 2007
@@ -3,49 +3,39 @@
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem.rffi import platform
 from pypy.rpython.extfunc import genericcallable
-from pypy.module.thread.os_thread import Bootstrapper
+from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
 from pypy.translator.tool.cbuild import cache_c_module
-from pypy.rpython.annlowlevel import cast_instance_to_base_ptr,\
-     cast_base_ptr_to_instance
+from pypy.rpython.lltypesystem import llmemory
 import thread, py
 from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.annotation import model as annmodel
 from pypy.rpython.lltypesystem.lltype import typeOf
+from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.nonconst import NonConstant
 
-class BaseBootstrapper:
-    def bootstrap(self):
-        pass
-
-class ThreadError(Exception):
+class error(Exception):
     def __init__(self, msg):
         self.msg = msg
 
-class Lock(object):
-    """ Container for low-level implementation
-    of a lock object
-    """
-    def __init__(self, ll_lock):
-        self._lock = ll_lock
-
+from pypy.tool.autopath import pypydir
+pypydir = py.path.local(pypydir)
+srcdir = pypydir.join('translator', 'c', 'src')
 includes = ['unistd.h', 'thread.h']
 
 def setup_thread_so():
-    from pypy.tool.autopath import pypydir
-    pypydir = py.path.local(pypydir)
-    srcdir = pypydir.join('translator', 'c', 'src')
-    modname = '_thread'
     files = [srcdir.join('thread.c')]
+    modname = '_thread'
     cache_c_module(files, modname, include_dirs=[str(srcdir)])
     return str(pypydir.join('_cache', modname)) + '.so'
 libraries = [setup_thread_so()]
 
 def llexternal(name, args, result):
     return rffi.llexternal(name, args, result, includes=includes,
-                           libraries=libraries)
+                           libraries=libraries, include_dirs=[str(srcdir)])
 
-CALLBACK = lltype.FuncType([rffi.VOIDP], rffi.VOIDP)
+CALLBACK = lltype.Ptr(lltype.FuncType([rffi.VOIDP], rffi.VOIDP))
 c_thread_start = llexternal('RPyThreadStart', [CALLBACK, rffi.VOIDP], rffi.INT)
-c_thread_get_ident = llexternal('RPyThreadGetIdent', [], lltype.Void)
+c_thread_get_ident = llexternal('RPyThreadGetIdent', [], rffi.INT)
 
 TLOCKP = rffi.COpaquePtr('struct RPyOpaque_ThreadLock', includes=includes)
 
@@ -54,63 +44,86 @@
                                  rffi.INT)
 c_thread_releaselock = llexternal('RPyThreadReleaseLock', [TLOCKP], lltype.Void)
 
-def ll_allocate_lock():
+def allocate_lock():
     ll_lock = lltype.malloc(TLOCKP.TO, flavor='raw')
     res = c_thread_lock_init(ll_lock)
     if res == -1:
-        raise ThreadError("out of resources")
+        raise error("out of resources")
     return Lock(ll_lock)
 
-def ll_acquire_lock(lock, waitflag):
-    return c_thread_acuirelock(lock._lock, waitflag)
-
-def ll_release_lock(lock):
-    try:
-        if ll_acquire_lock(lock, 0):
-            raise ThreadError("bad lock")
-    finally:
-        c_thread_releaselock(lock._lock)
+def _start_new_thread(x, y):
+    return thread.start_new_thread(x, (y,))
 
 def ll_start_new_thread(l_func, arg):
     l_arg = cast_instance_to_base_ptr(arg)
+    l_arg = rffi.cast(rffi.VOIDP, l_arg)
     ident = c_thread_start(l_func, l_arg)
     if ident == -1:
-        raise ThreadError("can't start new thread")
+        raise error("can't start new thread")
     return ident
 
 class LLStartNewThread(ExtRegistryEntry):
-    _about_ = ll_start_new_thread
-
+    _about_ = _start_new_thread
+    
     def compute_result_annotation(self, s_func, s_arg):
         bookkeeper = self.bookkeeper
-        assert s_func.is_constant(), "Cannot call ll_start_new_thread with non-constant function"
         s_result = bookkeeper.emulate_pbc_call(bookkeeper.position_key,
                                                s_func, [s_arg])
-        assert annmodel.s_None.contains(s_result), (
-            """thread.start_new_thread(f, arg): f() should return None""")
+        assert annmodel.s_None.contains(s_result)
         return annmodel.SomeInteger()
-
-    def compute_annotation_bk(self, bookkeeper):
-        return annmodel.SomePBC([bookkeeper.getdesc(self.instance)])
-
+    
     def specialize_call(self, hop):
         rtyper = hop.rtyper
-        bookkeeper = rtyper.annotator.bookkeeper
-        _callable = hop.args_s[0].const
+        bk = rtyper.annotator.bookkeeper
+        r_result = rtyper.getrepr(hop.s_result)
+        hop.exception_is_here()
         args_r = [rtyper.getrepr(s_arg) for s_arg in hop.args_s]
-        ll_arg = args_r[1].lowleveltype
-        _type = lltype.FuncType([ll_arg], lltype.Void)
-        funcptr = lltype.functionptr(_type, _callable.func_name,
+        _callable = hop.args_s[0].const
+        funcptr = lltype.functionptr(CALLBACK.TO, _callable.func_name,
                                      _callable=_callable)
-        r_result = rtyper.getrepr(hop.s_result)
-        ll_result = r_result.lowleveltype
-        args_s = [bookkeeper.immutablevalue(i) for i in [funcptr, ll_arg]]
+        func_s = bk.immutablevalue(funcptr)
+        s_args = [func_s, hop.args_s[1]]
         obj = rtyper.getannmixlevel().delayedfunction(
-            ll_start_new_thread, args_s, annmodel.SomeInteger())
-        vlist = [hop.inputconst(typeOf(obj), obj)] + hop.inputargs(*args_r)
-        hop.exception_is_here()
+            ll_start_new_thread, s_args, annmodel.SomeInteger())
+        bootstrap = rtyper.getannmixlevel().delayedfunction(
+            _callable, [hop.args_s[1]], annmodel.s_None)
+        vlist = [hop.inputconst(typeOf(obj), obj),
+                 hop.inputconst(typeOf(bootstrap), bootstrap),
+                 #hop.inputarg(args_r[0], 0),
+                 hop.inputarg(args_r[1], 1)]
         return hop.genop('direct_call', vlist, r_result)
 
-# a simple wrapper, not to expose C functions (is this really necessary?)
-def ll_get_ident():
+# wrappers...
+
+def get_ident():
     return c_thread_get_ident()
+
+def start_new_thread(x, y):
+    return _start_new_thread(x, y[0])
+
+class Lock(object):
+    """ Container for low-level implementation
+    of a lock object
+    """
+    def __init__(self, ll_lock):
+        self._lock = ll_lock
+
+    def acquire(self, flag):
+        return bool(c_thread_acuirelock(self._lock, int(flag)))
+
+    def release(self):
+        try:
+            if self.acquire(False):
+                # XXX the annotator trick to annotate it with non-const
+                # string, probably should be put into bltn-analyzers
+                raise error(NonConstant("bad lock"))
+        finally:
+            c_thread_releaselock(self._lock)
+
+    def fused_release_acquire(self):
+        self.release()
+        self.acquire(True)
+
+    def __del__(self):
+        lltype.free(self._lock, flavor='raw')
+

Modified: pypy/branch/pypy-more-rtti-inprogress/module/thread/test/test_ll_thread.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/module/thread/test/test_ll_thread.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/module/thread/test/test_ll_thread.py	Mon Aug 20 21:34:58 2007
@@ -1,40 +1,60 @@
 
 from pypy.module.thread.ll_thread import *
 from pypy.translator.c.test.test_genc import compile
+from pypy.rpython.lltypesystem import lltype
 import py
 
 def test_lock():
-    l = ll_allocate_lock()
-    ok1 = ll_acquire_lock(l, 1)
-    ok2 = ll_acquire_lock(l, 0)
-    ll_release_lock(l)
-    ok3 = ll_acquire_lock(l, 0)
+    l = allocate_lock()
+    ok1 = l.acquire(True)
+    ok2 = l.acquire(False)
+    l.release()
+    ok3 = l.acquire(False)
     res = ok1 and not ok2 and ok3
     assert res == 1
 
 def test_thread_error():
-    l = ll_allocate_lock()
-    py.test.raises(ThreadError, ll_release_lock, l)
+    l = allocate_lock()
+    try:
+        l.release()
+    except error:
+        pass
+    else:
+        py.test.fail("Did not raise")
 
-def test_thread_init_new():
-    """ This test works only after translation
-    """
-    py.test.skip("does not work")
+def test_start_new_thread():
     import time
-    import thread
-
-    class X(BaseBootstrapper):
+    class Y:
+        _alloc_flavor_ = 'raw'
+        
         def __init__(self):
             self.top = []
 
         def bootstrap(self):
-            self.top.append(1)
-    
+            self.top.append(get_ident())
+
     def f():
-        x = X()
-        ll_start_new_thread(X.bootstrap, x)
+        y = Y()
+        start_new_thread(Y.bootstrap, (y,))
         time.sleep(.3)
-        return len(x.top)
+        res = len(y.top)
+        lltype.free(y, flavor='raw')
+        return 1 == get_ident()
+
+    # for some reason, refcounting does not handle _alloc_flavor_ = 'raw'
+    # XXX is this testable on top of llinterp at all?
+    fn = compile(f, [], gcpolicy='boehm')
+    assert fn() == False
+
+def test_prebuilt_lock():
+    py.test.skip("Does not work (prebuilt opaque object)")
+    l = allocate_lock()
 
-    fn = compile(f, [])
-    assert fn() == 1
+    def f():
+        l.acquire(True)
+        l.release()
+
+    fn = compile(f, [], gcpolicy='boehm')
+    fn()
+
+    



More information about the Pypy-commit mailing list