[pypy-svn] r45428 - in pypy/dist/pypy/rpython: . module module/test test

fijal at codespeak.net fijal at codespeak.net
Sun Jul 29 16:34:45 CEST 2007


Author: fijal
Date: Sun Jul 29 16:34:42 2007
New Revision: 45428

Added:
   pypy/dist/pypy/rpython/test/test_extfuncregister.py   (contents, props changed)
Modified:
   pypy/dist/pypy/rpython/extfunc.py
   pypy/dist/pypy/rpython/extfuncregistry.py
   pypy/dist/pypy/rpython/module/ll_os.py
   pypy/dist/pypy/rpython/module/ll_termios.py
   pypy/dist/pypy/rpython/module/test/test_ll_os.py
   pypy/dist/pypy/rpython/module/test/test_posix.py
   pypy/dist/pypy/rpython/test/test_extfunc.py
Log:
(intermediate checkin) New, better way of lazily evaluating registering
externals. Not sure if this is an ultimate solution, but seems at least
like a better one.

Will break js code, will fix it later.


Modified: pypy/dist/pypy/rpython/extfunc.py
==============================================================================
--- pypy/dist/pypy/rpython/extfunc.py	(original)
+++ pypy/dist/pypy/rpython/extfunc.py	Sun Jul 29 16:34:42 2007
@@ -6,19 +6,56 @@
 
 import py, sys
 
-def lazy_register(func, register_func):
+def lazy_register(func_or_list, register_func):
     """ Lazily register external function. Will create a function,
     which explodes when llinterpd/translated, but does not explode
     earlier
     """
+    if isinstance(func_or_list, list):
+        funcs = func_or_list
+    else:
+        funcs = [func_or_list]
     try:
-        register_func()
+        return register_func()
     except:
         exc, exc_inst, tb = sys.exc_info()
-        class ExtRaisingEntry(ExtRegistryEntry):
-            _about_ = func
-            def compute_result_annotation(self, *args_s):
-                raise exc, exc_inst, tb
+        for func in funcs:
+            class ExtRaisingEntry(ExtRegistryEntry):
+                _about_ = func
+                def compute_result_annotation(self, *args_s):
+                    raise exc, exc_inst, tb
+
+def registering(func):
+    def decorator(method):
+        method._registering_func = func
+        return method
+    return decorator
+
+class LazyRegisteringMeta(type):
+    def __new__(self, _name, _type, _vars):
+        retval = type.__new__(self, _name, _type, _vars)
+        allfuncs = []
+        for varname in _vars:
+            attr = getattr(retval, varname)
+            f = getattr(attr, '_registering_func', None)
+            if f:
+                allfuncs.append(f)
+        instance = lazy_register(allfuncs, retval)
+        if instance is not None:
+            for varname in _vars:
+                attr = getattr(instance, varname)
+                f = getattr(attr, '_registering_func', None)
+                if f:
+                    lazy_register(f, attr)
+        retval.instance = instance
+        # override __init__ to avoid confusion
+        def raising(self):
+            raise TypeError("Cannot call __init__ directly, use cls.instance to access singleton")
+        retval.__init__ = raising
+        return retval
+
+class BaseLazyRegistering(object):
+    __metaclass__ = LazyRegisteringMeta
 
 class genericcallable(object):
     """ A way to specify the callable annotation, but deferred until
@@ -75,10 +112,10 @@
         hop.exception_is_here()
         return hop.genop('direct_call', vlist, r_result)
 
-def register_external(function, args, result=None, export_name=None,
-                      llimpl=None, ooimpl=None,
-                      llfakeimpl=None, oofakeimpl=None,
-                      annotation_hook=None):
+def _register_external(function, args, result=None, export_name=None,
+                       llimpl=None, ooimpl=None,
+                       llfakeimpl=None, oofakeimpl=None,
+                       annotation_hook=None):
     """
     function: the RPython function that will be rendered as an external function (e.g.: math.floor)
     args: a list containing the annotation of the arguments
@@ -113,6 +150,8 @@
     else:
         FunEntry.__name__ = function.func_name
 
+BaseLazyRegistering.register = staticmethod(_register_external)
+
 def is_external(func):
     if hasattr(func, 'value'):
         func = func.value

Modified: pypy/dist/pypy/rpython/extfuncregistry.py
==============================================================================
--- pypy/dist/pypy/rpython/extfuncregistry.py	(original)
+++ pypy/dist/pypy/rpython/extfuncregistry.py	Sun Jul 29 16:34:42 2007
@@ -1,7 +1,7 @@
 # this registry use the new interface for external functions
 # all the above declarations in extfunctable should be moved here at some point.
 
-from extfunc import register_external
+from extfunc import _register_external
 
 # ___________________________
 # math functions
@@ -24,7 +24,7 @@
     'floor', 'log', 'log10', 'sin', 'sinh', 'sqrt', 'tan', 'tanh'
     ]
 for name in simple_math_functions:
-    register_external(getattr(math, name), [float], float, "ll_math.ll_math_%s" % name)
+    _register_external(getattr(math, name), [float], float, "ll_math.ll_math_%s" % name)
 
 def frexp_hook():
     from pypy.rpython.extfunctable import record_call
@@ -52,9 +52,9 @@
     func = getattr(math, name)
     llfake = getattr(ll_math, 'll_math_%s' % name, None)
     oofake = getattr(oo_math, 'll_math_%s' % name, None)
-    register_external(func, args, res, 'll_math.ll_math_%s' % name,
-                      llfakeimpl=llfake, oofakeimpl=oofake,
-                      annotation_hook = hook)
+    _register_external(func, args, res, 'll_math.ll_math_%s' % name,
+                       llfakeimpl=llfake, oofakeimpl=oofake,
+                       annotation_hook = hook)
 
 
 # ___________________________
@@ -81,4 +81,4 @@
 for name, args, res in path_functions:
     func = getattr(os.path, name)
     llimpl = func_with_new_name(func, name)
-    register_external(func, args, res, 'll_os_path.ll_%s' % name, llimpl=llimpl)
+    _register_external(func, args, res, 'll_os_path.ll_%s' % name, llimpl=llimpl)

Modified: pypy/dist/pypy/rpython/module/ll_os.py
==============================================================================
--- pypy/dist/pypy/rpython/module/ll_os.py	(original)
+++ pypy/dist/pypy/rpython/module/ll_os.py	Sun Jul 29 16:34:42 2007
@@ -12,328 +12,340 @@
 from pypy.rlib.rarithmetic import r_longlong
 from pypy.tool.staticmethods import ClassMethods
 import stat
-from pypy.rpython.extfunc import ExtFuncEntry, register_external
+from pypy.rpython.extfunc import BaseLazyRegistering, registering
 from pypy.annotation.model import SomeString, SomeInteger, s_ImpossibleValue, \
     s_None
 from pypy.rpython.lltypesystem import rffi
 from pypy.rpython.lltypesystem.rffi import platform
 from pypy.rpython.lltypesystem import lltype
 
-# a simple, yet usefull factory
-def register_os_function_returning_int(fun, name, **kwds):
-    c_func = rffi.llexternal(name, [], rffi.INT, **kwds)
-    def c_func_lltypeimpl():
-        res = c_func()
-        if res == -1:
-            raise OSError(rffi.c_errno, "%s failed" % name)
-        return res
-    c_func_lltypeimpl.func_name = name + '_llimpl'
+class RegisterOs(BaseLazyRegistering):
+    def __init__(self):
+        self.getuid_incl = ['unistd.h', 'sys/types.h']
+    
+    # a simple, yet usefull factory
+    def register_os_function_returning_int(self, fun, name, **kwds):
+        c_func = rffi.llexternal(name, [], rffi.INT, **kwds)
+        def c_func_lltypeimpl():
+            res = c_func()
+            if res == -1:
+                raise OSError(rffi.c_errno, "%s failed" % name)
+            return res
+        c_func_lltypeimpl.func_name = name + '_llimpl'
 
-    register_external(fun, [], int, llimpl=c_func_lltypeimpl,
+        self.register(fun, [], int, llimpl=c_func_lltypeimpl,
                       export_name='ll_os.ll_os_' + name)
 
-# ------------------------------- os.execv ------------------------------
-
-if hasattr(os, 'execv'):
-
-    os_execv = rffi.llexternal('execv', [rffi.CCHARP, rffi.CCHARPP],
-                               rffi.INT)
-
-    def execv_lltypeimpl(path, args):
-        l_path = rffi.str2charp(path)
-        l_args = rffi.liststr2charpp(args)
-        os_execv(l_path, l_args)
-        rffi.free_charpp(l_args)
-        rffi.free_charp(l_path)
-        raise OSError(rffi.c_errno, "execv failed")
-
-    register_external(os.execv, [str, [str]], s_ImpossibleValue, llimpl=
-                      execv_lltypeimpl, export_name="ll_os.ll_os_execv")
-
-# ------------------------------- os.dup --------------------------------
-
-os_dup = rffi.llexternal('dup', [rffi.INT], rffi.INT)
+    if hasattr(os, 'execv'):
+        @registering(os.execv)
+        def register_os_execv(self):
+            os_execv = rffi.llexternal('execv', [rffi.CCHARP, rffi.CCHARPP],
+                                       rffi.INT)
+
+            def execv_lltypeimpl(path, args):
+                l_path = rffi.str2charp(path)
+                l_args = rffi.liststr2charpp(args)
+                os_execv(l_path, l_args)
+                rffi.free_charpp(l_args)
+                rffi.free_charp(l_path)
+                raise OSError(rffi.c_errno, "execv failed")
+
+            self.register(os.execv, [str, [str]], s_ImpossibleValue, llimpl=
+                          execv_lltypeimpl, export_name="ll_os.ll_os_execv")
+
+    @registering(os.dup)
+    def register_os_dup(self):
+        os_dup = rffi.llexternal('dup', [rffi.INT], rffi.INT)
+
+        def dup_lltypeimpl(fd):
+            newfd = rffi.cast(lltype.Signed, os_dup(rffi.cast(rffi.INT, fd)))
+            if newfd == -1:
+                raise OSError(rffi.c_errno, "dup failed")
+            return newfd
+        
+        self.register(os.dup, [int], int, llimpl=dup_lltypeimpl,
+                      export_name="ll_os.ll_os_dup", oofakeimpl=os.dup)
+
+    @registering(os.dup2)
+    def register_os_dup2(self):
+        os_dup2 = rffi.llexternal('dup2', [rffi.INT, rffi.INT], rffi.INT)
 
-def dup_lltypeimpl(fd):
-    newfd = rffi.cast(lltype.Signed, os_dup(rffi.cast(rffi.INT, fd)))
-    if newfd == -1:
-        raise OSError(rffi.c_errno, "dup failed")
-    return newfd
-register_external(os.dup, [int], int, llimpl=dup_lltypeimpl,
-                  export_name="ll_os.ll_os_dup", oofakeimpl=os.dup)
-
-# ------------------------------- os.dup2 -------------------------------
+        def dup2_lltypeimpl(fd, newfd):
+            error = rffi.cast(lltype.Signed, os_dup2(rffi.cast(rffi.INT, fd),
+                                             rffi.cast(rffi.INT, newfd)))
+            if error == -1:
+                raise OSError(rffi.c_errno, "dup2 failed")
 
-os_dup2 = rffi.llexternal('dup2', [rffi.INT, rffi.INT], rffi.INT)
+        self.register(os.dup2, [int, int], s_None, llimpl=dup2_lltypeimpl,
+                      export_name="ll_os.ll_os_dup2")
 
-def dup2_lltypeimpl(fd, newfd):
-    error = rffi.cast(lltype.Signed, os_dup2(rffi.cast(rffi.INT, fd),
-                                             rffi.cast(rffi.INT, newfd)))
-    if error == -1:
-        raise OSError(rffi.c_errno, "dup2 failed")
-register_external(os.dup2, [int, int], s_None, llimpl=dup2_lltypeimpl,
-                  export_name="ll_os.ll_os_dup2")
-
-# ------------------------------- os.utime ------------------------------
-
-TIME_T = rffi.INT    # XXX do the right thing
-UTIMEBUFP = rffi.CStruct('utimbuf', ('actime', TIME_T),
-                                    ('modtime', TIME_T))
-
-# XXX sys/types.h is not portable at all
-ros_utime = rffi.llexternal('utime', [rffi.CCHARP, UTIMEBUFP], rffi.INT,
-                            includes=['utime.h', 'sys/types.h'])
-
-def utime_null_lltypeimpl(path):
-    l_path = rffi.str2charp(path)
-    error = rffi.cast(lltype.Signed, ros_utime(l_path,
-                                               lltype.nullptr(UTIMEBUFP.TO)))
-    rffi.free_charp(l_path)
-    if error == -1:
-        raise OSError(rffi.c_errno, "utime_null failed")
-register_external(ros.utime_null, [str], s_None, "ll_os.utime_null",
-                  llimpl=utime_null_lltypeimpl)
-
-def utime_tuple_lltypeimpl(path, tp):
-    # XXX right now they're all ints, might change in future
-    # XXX does not use utimes, even when available
-    l_path = rffi.str2charp(path)
-    l_utimebuf = lltype.malloc(UTIMEBUFP.TO, flavor='raw')
-    actime, modtime = tp
-    l_utimebuf.c_actime, l_utimebuf.c_modtime = int(actime), int(modtime)
-    error = rffi.cast(lltype.Signed, ros_utime(l_path, l_utimebuf))
-    rffi.free_charp(l_path)
-    lltype.free(l_utimebuf, flavor='raw')
-    if error == -1:
-        raise OSError(rffi.c_errno, "utime_tuple failed")
-register_external(ros.utime_tuple, [str, (float, float)], s_None, "ll_os.utime_tuple",
-                  llimpl=utime_tuple_lltypeimpl)
-
-# ------------------------------- os.setsid -----------------------------
-
-if hasattr(os, 'setsid'):
-    os_setsid = rffi.llexternal('setsid', [], rffi.PID_T,
-                                includes=['unistd.h'])
-
-    def setsid_lltypeimpl():
-        result = rffi.cast(lltype.Signed, os_setsid())
-        if result == -1:
-            raise OSError(rffi.c_errno, "os_setsid failed")
-        return result
-
-    register_external(os.setsid, [], int, export_name="ll_os.ll_os_setsid",
-                      llimpl=setsid_lltypeimpl)
-
-# ------------------------------- os.uname ------------------------------
-
-if False and hasattr(os, 'uname'): # make it more portable
-    lgt = platform.intdefined('_UTSNAME_LENGTH', includes=['sys/utsname.h'])
-    UTCHARP = lltype.FixedSizeArray(lltype.Char, lgt)
-    fields = [('sysname', UTCHARP),
-              ('nodename', UTCHARP),
-              ('release', UTCHARP),
-              ('version', UTCHARP),
-              ('machine', UTCHARP),
-              ('domainname', UTCHARP)]
-    UTSNAMEP = rffi.CStruct('utsname', *fields)
+    @registering(os.utime)
+    def register_os_utime(self):
+        TIME_T = rffi.INT    # XXX do the right thing
+        UTIMEBUFP = rffi.CStruct('utimbuf', ('actime', TIME_T),
+                                 ('modtime', TIME_T))
+
+        # XXX sys/types.h is not portable at all
+        ros_utime = rffi.llexternal('utime', [rffi.CCHARP, UTIMEBUFP],
+                                    rffi.INT,
+                                    includes=['utime.h', 'sys/types.h'])
+
+        def utime_null_lltypeimpl(path):
+            l_path = rffi.str2charp(path)
+            error = rffi.cast(lltype.Signed, ros_utime(l_path,
+                              lltype.nullptr(UTIMEBUFP.TO)))
+            rffi.free_charp(l_path)
+            if error == -1:
+                raise OSError(rffi.c_errno, "utime_null failed")
+            
+        self.register(ros.utime_null, [str], s_None, "ll_os.utime_null",
+                      llimpl=utime_null_lltypeimpl)
+
+        def utime_tuple_lltypeimpl(path, tp):
+            # XXX right now they're all ints, might change in future
+            # XXX does not use utimes, even when available
+            l_path = rffi.str2charp(path)
+            l_utimebuf = lltype.malloc(UTIMEBUFP.TO, flavor='raw')
+            actime, modtime = tp
+            l_utimebuf.c_actime, l_utimebuf.c_modtime = int(actime), int(modtime)
+            error = rffi.cast(lltype.Signed, ros_utime(l_path, l_utimebuf))
+            rffi.free_charp(l_path)
+            lltype.free(l_utimebuf, flavor='raw')
+            if error == -1:
+                raise OSError(rffi.c_errno, "utime_tuple failed")
+        
+        self.register(ros.utime_tuple, [str, (float, float)], s_None,
+                      "ll_os.utime_tuple",
+                      llimpl=utime_tuple_lltypeimpl)
+
+    if hasattr(os, 'setsid'):
+        @registering(os.setsid)
+        def register_os_setsid(self):
+            os_setsid = rffi.llexternal('setsid', [], rffi.PID_T,
+                                        includes=['unistd.h'])
+
+            def setsid_lltypeimpl():
+                result = rffi.cast(lltype.Signed, os_setsid())
+                if result == -1:
+                    raise OSError(rffi.c_errno, "os_setsid failed")
+                return result
+
+            self.register(os.setsid, [], int, export_name="ll_os.ll_os_setsid",
+                          llimpl=setsid_lltypeimpl)
+
+    if False and hasattr(os, 'uname'): # make it more portable
+        @registering(os.uname)
+        def register_os_uname(self):
+            lgt = platform.intdefined('_UTSNAME_LENGTH',
+                                      includes=['sys/utsname.h'])
+            UTCHARP = lltype.FixedSizeArray(lltype.Char, lgt)
+            fields = [('sysname', UTCHARP),
+                      ('nodename', UTCHARP),
+                      ('release', UTCHARP),
+                      ('version', UTCHARP),
+                      ('machine', UTCHARP),
+                      ('domainname', UTCHARP)]
+            UTSNAMEP = rffi.CStruct('utsname', *fields)
     
-    os_uname = rffi.llexternal('uname', [UTSNAMEP], rffi.INT,
-                               includes=['sys/utsname.h'])
+            os_uname = rffi.llexternal('uname', [UTSNAMEP], rffi.INT,
+                                       includes=['sys/utsname.h'])
 
-    def utcharp2str(cp):
-        l = []
-        i = 0
-        while cp[i] != '\x00' and i < lgt:
-            l.append(cp[i])
-            i += 1
-        return "".join(l)
-
-    def uname_lltypeimpl():
-        l_utsbuf = lltype.malloc(UTSNAMEP.TO, flavor='raw')
-        result = os_uname(l_utsbuf)
-        if result == -1:
-            raise OSError(rffi.c_errno, "os_uname failed")
-        fields = [l_utsbuf.c_sysname, l_utsbuf.c_nodename,
-                l_utsbuf.c_release, l_utsbuf.c_version, l_utsbuf.c_machine]
-        l = [utcharp2str(i) for i in fields]
-        retval = (l[0], l[1], l[2], l[3], l[4])
-        lltype.free(l_utsbuf, flavor='raw')
-        return retval
-
-    register_external(os.uname, [], (str, str, str, str, str),
-                      "ll_os.ll_uname", llimpl=uname_lltypeimpl)
-
-# ------------------------------- os.getuid/geteuid ---------------------
-
-getuid_incl = ['unistd.h', 'sys/types.h']
-register_os_function_returning_int(os.getuid, 'getuid',
-                                   includes=getuid_incl)
-register_os_function_returning_int(os.geteuid, 'geteuid',
-                                   includes=getuid_incl)
-
-# ------------------------------- os.open -------------------------------
-
-if os.name == 'nt':
-    mode_t = rffi.INT
-else:
-    mode_t = rffi.MODE_T
-
-os_open = rffi.llexternal('open', [rffi.CCHARP, rffi.INT, mode_t],
-                          rffi.INT)
-
-def os_open_lltypeimpl(path, flags, mode):
-    l_path = rffi.str2charp(path)
-    result = rffi.cast(lltype.Signed, os_open(l_path,
-                                              rffi.cast(rffi.INT, flags),
-                                              rffi.cast(mode_t, mode)))
-    rffi.free_charp(l_path)
-    if result == -1:
-        raise OSError(rffi.c_errno, "os_open failed")
-    return result
+            def utcharp2str(cp):
+                l = []
+                i = 0
+                while cp[i] != '\x00' and i < lgt:
+                    l.append(cp[i])
+                    i += 1
+                return "".join(l)
+
+            def uname_lltypeimpl():
+                l_utsbuf = lltype.malloc(UTSNAMEP.TO, flavor='raw')
+                result = os_uname(l_utsbuf)
+                if result == -1:
+                    raise OSError(rffi.c_errno, "os_uname failed")
+                fields = [l_utsbuf.c_sysname, l_utsbuf.c_nodename,
+                          l_utsbuf.c_release, l_utsbuf.c_version,
+                          l_utsbuf.c_machine]
+                l = [utcharp2str(i) for i in fields]
+                retval = (l[0], l[1], l[2], l[3], l[4])
+                lltype.free(l_utsbuf, flavor='raw')
+                return retval
+
+            self.register(os.uname, [], (str, str, str, str, str),
+                          "ll_os.ll_uname", llimpl=uname_lltypeimpl)
+
+    @registering(os.getuid)
+    def register_os_getuid(self):
+        self.register_os_function_returning_int(os.getuid, 'getuid',
+                                                includes=self.getuid_incl)
+
+    @registering(os.geteuid)
+    def register_os_geteuid(self):
+        self.register_os_function_returning_int(os.geteuid, 'geteuid',
+                                                includes=self.getuid_incl)
+
+    @registering(os.open)
+    def register_os_open(self):
+        if os.name == 'nt':
+            mode_t = rffi.INT
+        else:
+            mode_t = rffi.MODE_T
+        os_open = rffi.llexternal('open', [rffi.CCHARP, rffi.INT, mode_t],
+                                  rffi.INT)
+
+        def os_open_lltypeimpl(path, flags, mode):
+            l_path = rffi.str2charp(path)
+            result = rffi.cast(lltype.Signed, os_open(l_path,
+                               rffi.cast(rffi.INT, flags),
+                               rffi.cast(mode_t, mode)))
+            rffi.free_charp(l_path)
+            if result == -1:
+                raise OSError(rffi.c_errno, "os_open failed")
+            return result
 
-def os_open_oofakeimpl(o_path, flags, mode):
-    return os.open(o_path._str, flags, mode)
+        def os_open_oofakeimpl(o_path, flags, mode):
+            return os.open(o_path._str, flags, mode)
 
-register_external(os.open, [str, int, int], int, "ll_os.ll_os_open",
-                  llimpl=os_open_lltypeimpl, oofakeimpl=os_open_oofakeimpl)
+        self.register(os.open, [str, int, int], int, "ll_os.ll_os_open",
+                      llimpl=os_open_lltypeimpl, oofakeimpl=os_open_oofakeimpl)
 
 # ------------------------------- os.read -------------------------------
 
-os_read = rffi.llexternal('read', [rffi.INT, rffi.VOIDP, rffi.SIZE_T],
-                          rffi.SIZE_T)
-
-def os_read_lltypeimpl(fd, count):
-    if count < 0:
-        raise OSError(errno.EINVAL, None)
-    inbuf = lltype.malloc(rffi.CCHARP.TO, count, flavor='raw')
-    try:
-        got = rffi.cast(lltype.Signed, os_read(rffi.cast(rffi.INT, fd),
-                                               inbuf,
-                                               rffi.cast(rffi.SIZE_T, count)))
-        if got < 0:
-            raise OSError(rffi.c_errno, "os_read failed")
-        # XXX too many copies of the data!
-        l = [inbuf[i] for i in range(got)]
-    finally:
-        lltype.free(inbuf, flavor='raw')
-    return ''.join(l)
-
-def os_read_oofakeimpl(fd, count):
-    return OOSupport.to_rstr(os.read(fd, count))
-
-register_external(os.read, [int, int], str, "ll_os.ll_os_read",
-                  llimpl=os_read_lltypeimpl, oofakeimpl=os_read_oofakeimpl)
-
-# '--sandbox' support
-def os_read_marshal_input(msg, fd, buf, size):
-    msg.packnum(rffi.cast(lltype.Signed, fd))
-    msg.packsize_t(size)
-def os_read_unmarshal_output(msg, fd, buf, size):
-    data = msg.nextstring()
-    if len(data) > rffi.cast(lltype.Signed, size):
-        raise OverflowError
-    for i in range(len(data)):
-        buf[i] = data[i]
-    return rffi.cast(rffi.SIZE_T, len(data))
-os_read._obj._marshal_input = os_read_marshal_input
-os_read._obj._unmarshal_output = os_read_unmarshal_output
-
-# ------------------------------- os.write ------------------------------
-
-os_write = rffi.llexternal('write', [rffi.INT, rffi.VOIDP, rffi.SIZE_T],
-                           rffi.SIZE_T)
-
-def os_write_lltypeimpl(fd, data):
-    count = len(data)
-    outbuf = lltype.malloc(rffi.CCHARP.TO, count, flavor='raw')
-    try:
-        for i in range(count):
-            outbuf[i] = data[i]
-        written = rffi.cast(lltype.Signed, os_write(rffi.cast(rffi.INT, fd),
-                                                    outbuf,
-                                                rffi.cast(rffi.SIZE_T, count)))
-        if written < 0:
-            raise OSError(rffi.c_errno, "os_write failed")
-    finally:
-        lltype.free(outbuf, flavor='raw')
-    return written
-
-def os_write_oofakeimpl(fd, data):
-    return os.write(fd, OOSupport.from_rstr(data))
-
-register_external(os.write, [int, str], SomeInteger(nonneg=True)
-                  , "ll_os.ll_os_write",
-                  llimpl=os_write_lltypeimpl, oofakeimpl=os_write_oofakeimpl)
-
-# '--sandbox' support
-def os_write_marshal_input(msg, fd, buf, size):
-    msg.packnum(rffi.cast(lltype.Signed, fd))
-    msg.packbuf(buf, 0, rffi.cast(lltype.Signed, size))
-os_write._obj._marshal_input = os_write_marshal_input
-
-# ------------------------------- os.close ------------------------------
-
-os_close = rffi.llexternal('close', [rffi.INT], rffi.INT)
-
-def close_lltypeimpl(fd):
-    error = rffi.cast(lltype.Signed, os_close(rffi.cast(rffi.INT, fd)))
-    if error == -1:
-        raise OSError(rffi.c_errno, "close failed")
-
-register_external(os.close, [int], s_None, llimpl=close_lltypeimpl,
-                  export_name="ll_os.ll_os_close", oofakeimpl=os.close)
-
-# ------------------------------- os.* ----------------------------------
-
-w_star = ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED',
-          'WIFSIGNALED', 'WIFEXITED', 'WEXITSTATUS',
-          'WSTOPSIG', 'WTERMSIG']
-# last 3 are returning int
-w_star_returning_int = dict.fromkeys(w_star[-3:])
-
-def declare_new_w_star(name):
-    """ stupid workaround for the python late-binding
-    'feature'
-    """
-    def fake(status):
-        return int(getattr(os, name)(status))
-    fake.func_name = 'fake_' + name
-
-    
-    os_c_func = rffi.llexternal(name, [lltype.Signed],
-                                lltype.Signed, _callable=fake,
-                                includes=["sys/wait.h", "sys/types.h"])
+    @registering(os.read)
+    def register_os_read(self):
+        os_read = rffi.llexternal('read', [rffi.INT, rffi.VOIDP, rffi.SIZE_T],
+                                  rffi.SIZE_T)
+
+        def os_read_lltypeimpl(fd, count):
+            if count < 0:
+                raise OSError(errno.EINVAL, None)
+            inbuf = lltype.malloc(rffi.CCHARP.TO, count, flavor='raw')
+            try:
+                got = rffi.cast(lltype.Signed, os_read(rffi.cast(rffi.INT, fd),
+                                inbuf, rffi.cast(rffi.SIZE_T, count)))
+                if got < 0:
+                    raise OSError(rffi.c_errno, "os_read failed")
+                # XXX too many copies of the data!
+                l = [inbuf[i] for i in range(got)]
+            finally:
+                lltype.free(inbuf, flavor='raw')
+            return ''.join(l)
+
+        def os_read_oofakeimpl(fd, count):
+            return OOSupport.to_rstr(os.read(fd, count))
+
+        self.register(os.read, [int, int], str, "ll_os.ll_os_read",
+                      llimpl=os_read_lltypeimpl, oofakeimpl=os_read_oofakeimpl)
+
+        # '--sandbox' support
+        def os_read_marshal_input(msg, fd, buf, size):
+            msg.packnum(rffi.cast(lltype.Signed, fd))
+            msg.packsize_t(size)
+        def os_read_unmarshal_output(msg, fd, buf, size):
+            data = msg.nextstring()
+            if len(data) > rffi.cast(lltype.Signed, size):
+                raise OverflowError
+            for i in range(len(data)):
+                buf[i] = data[i]
+            return rffi.cast(rffi.SIZE_T, len(data))
+        os_read._obj._marshal_input = os_read_marshal_input
+        os_read._obj._unmarshal_output = os_read_unmarshal_output
+
+    @registering(os.write)
+    def register_os_write(self):
+        os_write = rffi.llexternal('write', [rffi.INT, rffi.VOIDP,
+                                   rffi.SIZE_T], rffi.SIZE_T)
+
+        def os_write_lltypeimpl(fd, data):
+            count = len(data)
+            outbuf = lltype.malloc(rffi.CCHARP.TO, count, flavor='raw')
+            try:
+                for i in range(count):
+                    outbuf[i] = data[i]
+                written = rffi.cast(lltype.Signed, os_write(
+                    rffi.cast(rffi.INT, fd),
+                    outbuf, rffi.cast(rffi.SIZE_T, count)))
+                if written < 0:
+                    raise OSError(rffi.c_errno, "os_write failed")
+            finally:
+                lltype.free(outbuf, flavor='raw')
+            return written
+
+        def os_write_oofakeimpl(fd, data):
+            return os.write(fd, OOSupport.from_rstr(data))
+
+        self.register(os.write, [int, str], SomeInteger(nonneg=True),
+                      "ll_os.ll_os_write", llimpl=os_write_lltypeimpl,
+                      oofakeimpl=os_write_oofakeimpl)
+
+        # '--sandbox' support
+        def os_write_marshal_input(msg, fd, buf, size):
+            msg.packnum(rffi.cast(lltype.Signed, fd))
+            msg.packbuf(buf, 0, rffi.cast(lltype.Signed, size))
+        os_write._obj._marshal_input = os_write_marshal_input
+
+    @registering(os.close)
+    def register_os_close(self):
+        os_close = rffi.llexternal('close', [rffi.INT], rffi.INT)
+        
+        def close_lltypeimpl(fd):
+            error = rffi.cast(lltype.Signed, os_close(rffi.cast(rffi.INT, fd)))
+            if error == -1:
+                raise OSError(rffi.c_errno, "close failed")
+
+        self.register(os.close, [int], s_None, llimpl=close_lltypeimpl,
+                      export_name="ll_os.ll_os_close", oofakeimpl=os.close)
+
+    # ------------------------------- os.W* ---------------------------------
+
+    w_star = ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED',
+              'WIFSIGNALED', 'WIFEXITED', 'WEXITSTATUS',
+              'WSTOPSIG', 'WTERMSIG']
+    # last 3 are returning int
+    w_star_returning_int = dict.fromkeys(w_star[-3:])
+
+    def declare_new_w_star(self, name):
+        """ stupid workaround for the python late-binding
+        'feature'
+        """
+        def fake(status):
+            return int(getattr(os, name)(status))
+        fake.func_name = 'fake_' + name
+
+        os_c_func = rffi.llexternal(name, [lltype.Signed],
+                                    lltype.Signed, _callable=fake,
+                                    includes=["sys/wait.h", "sys/types.h"])
     
-    if name in w_star_returning_int:
-        def lltypeimpl(status):
-            return os_c_func(status)
-        resulttype = int
-    else:
-        def lltypeimpl(status):
-            return bool(os_c_func(status))
-        resulttype = bool
-    lltypeimpl.func_name = name + '_lltypeimpl'
-    register_external(getattr(os, name), [int], resulttype, "ll_os."+name,
+        if name in self.w_star_returning_int:
+            def lltypeimpl(status):
+                return os_c_func(status)
+            resulttype = int
+        else:
+            def lltypeimpl(status):
+                return bool(os_c_func(status))
+            resulttype = bool
+        lltypeimpl.func_name = name + '_lltypeimpl'
+        self.register(getattr(os, name), [int], resulttype, "ll_os."+name,
                       llimpl=lltypeimpl)
 
+    for name in w_star:
+        if hasattr(os, name):
+            locals()['register_w_' + name] = registering(getattr(os, name))(
+                     lambda self, xname=name : self.declare_new_w_star(xname))
+
+    if hasattr(os, 'ttyname'):
+        @registering(os.ttyname)
+        def register_os_ttyname(self):
+            os_ttyname = rffi.llexternal('ttyname', [lltype.Signed], rffi.CCHARP)
+
+            def ttyname_lltypeimpl(fd):
+                l_name = os_ttyname(fd)
+                if not l_name:
+                    raise OSError(rffi.c_errno, "ttyname raised")
+                return rffi.charp2str(l_name)
 
-for name in w_star:
-    if hasattr(os, name):
-        declare_new_w_star(name)
-
-# ------------------------------- os.ttyname ----------------------------
-
-if hasattr(os, 'ttyname'):
-    os_ttyname = rffi.llexternal('ttyname', [lltype.Signed], rffi.CCHARP)
-
-    def ttyname_lltypeimpl(fd):
-        l_name = os_ttyname(fd)
-        if not l_name:
-            raise OSError(rffi.c_errno, "ttyname raised")
-        return rffi.charp2str(l_name)
-
-    register_external(os.ttyname, [int], str, "ll_os.ttyname",
-                      llimpl=ttyname_lltypeimpl)
+            self.register(os.ttyname, [int], str, "ll_os.ttyname",
+                          llimpl=ttyname_lltypeimpl)
 
 class BaseOS:
     __metaclass__ = ClassMethods

Modified: pypy/dist/pypy/rpython/module/ll_termios.py
==============================================================================
--- pypy/dist/pypy/rpython/module/ll_termios.py	(original)
+++ pypy/dist/pypy/rpython/module/ll_termios.py	Sun Jul 29 16:34:42 2007
@@ -8,18 +8,19 @@
 import termios
 from pypy.rpython.lltypesystem import rffi
 from pypy.rpython.lltypesystem import lltype
-from pypy.rpython.extfunc import register_external
+from pypy.rpython.extfunc import lazy_register, _register_external
 from pypy.rlib.rarithmetic import intmask
 from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.annotation import model as annmodel
 from pypy.rpython import rclass
 from pypy.rlib import rtermios
+from pypy.rpython.lltypesystem.rffi import platform
+
+includes = ['termios.h', 'unistd.h']
 
-# XXX is this portable? well.. not at all, ideally
-# I would like to have NCCS = CLaterConstant(NCCS)
 TCFLAG_T = rffi.UINT
 CC_T = rffi.UCHAR
-NCCS = 32
+NCCS = platform.intdefined('NCCS', includes=includes)
 SPEED_T = rffi.UINT
 INT = rffi.INT
 
@@ -28,8 +29,6 @@
 
 termios.error.__init__ = termios_error_init
 
-includes = ['termios.h', 'unistd.h']
-
 TERMIOSP = rffi.CStruct('termios', ('c_iflag', TCFLAG_T), ('c_oflag', TCFLAG_T),
                         ('c_cflag', TCFLAG_T), ('c_lflag', TCFLAG_T),
                         ('c_cc', lltype.FixedSizeArray(CC_T, NCCS)))
@@ -37,7 +36,6 @@
 def c_external(name, args, result):
     return rffi.llexternal(name, args, result, includes=includes)
 
-c_tcgetattr = c_external('tcgetattr', [INT, TERMIOSP], INT)
 c_tcsetattr = c_external('tcsetattr', [INT, INT, TERMIOSP], INT)
 c_cfgetispeed = c_external('cfgetispeed', [TERMIOSP], SPEED_T)
 c_cfgetospeed = c_external('cfgetospeed', [TERMIOSP], SPEED_T)
@@ -52,6 +50,8 @@
 #    def __init__(self, num, msg):
 #        self.args = (num, msg)
 
+c_tcgetattr = c_external('tcgetattr', [INT, TERMIOSP], INT)
+
 def tcgetattr_llimpl(fd):
     c_struct = lltype.malloc(TERMIOSP.TO, flavor='raw')
     error = c_tcgetattr(fd, c_struct)
@@ -68,8 +68,8 @@
     finally:
         lltype.free(c_struct, flavor='raw')
 
-register_external(rtermios.tcgetattr, [int], (int, int, int, int, int, int, [str]),
-                  llimpl=tcgetattr_llimpl, export_name='termios.tcgetattr')
+_register_external(rtermios.tcgetattr, [int], (int, int, int, int, int, int, [str]),
+                   llimpl=tcgetattr_llimpl, export_name='termios.tcgetattr')
 
 def tcsetattr_llimpl(fd, when, attributes):
     c_struct = lltype.malloc(TERMIOSP.TO, flavor='raw')
@@ -91,7 +91,7 @@
         lltype.free(c_struct, flavor='raw')
 
 r_uint = rffi.r_uint
-register_external(rtermios.tcsetattr, [int, int, (r_uint, r_uint, r_uint,
+_register_external(rtermios.tcsetattr, [int, int, (r_uint, r_uint, r_uint,
                   r_uint, r_uint, r_uint, [str])], llimpl=tcsetattr_llimpl,
                   export_name='termios.tcsetattr')
 
@@ -101,7 +101,7 @@
     error = c_tcsendbreak(fd, duration)
     if error == -1:
         raise termios.error(error, 'tcsendbreak failed')
-register_external(termios.tcsendbreak, [int, int],
+_register_external(termios.tcsendbreak, [int, int],
                   llimpl=tcsendbreak_llimpl,
                   export_name='termios.tcsendbreak')
 
@@ -109,19 +109,19 @@
     error = c_tcdrain(fd)
     if error == -1:
         raise termios.error(error, 'tcdrain failed')
-register_external(termios.tcdrain, [int], llimpl=tcdrain_llimpl,
+_register_external(termios.tcdrain, [int], llimpl=tcdrain_llimpl,
                   export_name='termios.tcdrain')
 
 def tcflush_llimpl(fd, queue_selector):
     error = c_tcflush(fd, queue_selector)
     if error == -1:
         raise termios.error(error, 'tcflush failed')
-register_external(termios.tcflush, [int, int], llimpl=tcflush_llimpl,
+_register_external(termios.tcflush, [int, int], llimpl=tcflush_llimpl,
                   export_name='termios.tcflush')
 
 def tcflow_llimpl(fd, action):
     error = c_tcflow(fd, action)
     if error == -1:
         raise termios.error(error, 'tcflow failed')
-register_external(termios.tcflow, [int, int], llimpl=tcflow_llimpl,
+_register_external(termios.tcflow, [int, int], llimpl=tcflow_llimpl,
                   export_name='termios.tcflow')

Modified: pypy/dist/pypy/rpython/module/test/test_ll_os.py
==============================================================================
--- pypy/dist/pypy/rpython/module/test/test_ll_os.py	(original)
+++ pypy/dist/pypy/rpython/module/test/test_ll_os.py	Sun Jul 29 16:34:42 2007
@@ -104,8 +104,8 @@
     assert result == compared_with
 
 def test_os_wstar():
-    from pypy.rpython.module.ll_os import w_star
-    for name in w_star:
+    from pypy.rpython.module.ll_os import RegisterOs
+    for name in RegisterOs.w_star:
         def fun(s):
             return getattr(os, name)(s)
 

Modified: pypy/dist/pypy/rpython/module/test/test_posix.py
==============================================================================
--- pypy/dist/pypy/rpython/module/test/test_posix.py	(original)
+++ pypy/dist/pypy/rpython/module/test/test_posix.py	Sun Jul 29 16:34:42 2007
@@ -108,7 +108,7 @@
     del BaseTestPosix.test_ftruncate
 
 class TestLLtype(BaseTestPosix, LLRtypeMixin):
-    if hasattr(os, 'uname'):
+    if False and hasattr(os, 'uname'):
         def test_os_uname(self):
             for num in range(5):
                 def fun():

Modified: pypy/dist/pypy/rpython/test/test_extfunc.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_extfunc.py	(original)
+++ pypy/dist/pypy/rpython/test/test_extfunc.py	Sun Jul 29 16:34:42 2007
@@ -1,5 +1,5 @@
 
-from pypy.rpython.extfunc import ExtFuncEntry, register_external,\
+from pypy.rpython.extfunc import ExtFuncEntry, _register_external,\
      is_external, lazy_register
 from pypy.annotation import model as annmodel
 from pypy.annotation.annrpython import RPythonAnnotator
@@ -79,7 +79,7 @@
 def dd():
     pass
 
-register_external(dd, [int], int)
+_register_external(dd, [int], int)
 
 def test_register_external_signature():
     def f():
@@ -98,7 +98,7 @@
     an argument so that register_external's behavior for tuple-taking functions
     can be verified.
     """
-register_external(function_with_tuple_arg, [(int,)], int)
+_register_external(function_with_tuple_arg, [(int,)], int)
 
 def test_register_external_tuple_args():
     """
@@ -118,11 +118,11 @@
 
 def function_with_list():
     pass
-register_external(function_with_list, [[int]], int)
+_register_external(function_with_list, [[int]], int)
 
 def function_returning_list():
     pass
-register_external(function_returning_list, [], [int])
+_register_external(function_returning_list, [], [int])
 
 def test_register_external_return_goes_back():
     """
@@ -141,7 +141,7 @@
 
 def function_withspecialcase(arg):
     return repr(arg)
-register_external(function_withspecialcase, args=None, result=str)
+_register_external(function_withspecialcase, args=None, result=str)
 
 def test_register_external_specialcase():
     def f():
@@ -153,19 +153,3 @@
     a = RPythonAnnotator(policy=policy)
     s = a.build_types(f, [])
     assert isinstance(s, annmodel.SomeString)
-
-def test_lazy_register():
-    def f():
-        return 3
-
-    def g():
-        return f()
-    
-    def reg_func():
-        1/0
-
-    lazy_register(f, reg_func)
-
-    from pypy.rpython.test.test_llinterp import interpret
-
-    interpret(g, [])

Added: pypy/dist/pypy/rpython/test/test_extfuncregister.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/test/test_extfuncregister.py	Sun Jul 29 16:34:42 2007
@@ -0,0 +1,73 @@
+
+""" A small test suite for discovering whether lazy registration
+of register_external functions work as intendet
+"""
+
+import py
+from pypy.rpython.extfunc import lazy_register, BaseLazyRegistering, \
+     registering
+from pypy.rpython.test.test_llinterp import interpret
+
+def test_lazy_register():
+    def f():
+        return 3
+
+    def g():
+        return f()
+    
+    def reg_func():
+        1/0
+
+    lazy_register(f, reg_func)
+
+    py.test.raises(ZeroDivisionError, interpret, g, [])
+
+def test_lazy_register_class_raising():
+    def f():
+        return 3
+
+    def g():
+        return 3
+    
+    class LazyRegister(BaseLazyRegistering):
+        def __init__(self):
+            self.stuff = 8
+            self.x = []
+
+        @registering(f)
+        def register_f(self):
+            self.x.append(1)
+            1/0
+
+        @registering(g)
+        def register_g(self):
+            self.x.append(2)
+            self.register(g, [], int, llimpl=lambda : self.stuff)
+
+    py.test.raises(TypeError, "LazyRegister()")
+    assert LazyRegister.instance.x == [1, 2]
+    py.test.raises(ZeroDivisionError, interpret, lambda : f(), [])
+    assert interpret(lambda : g(), []) == 8
+
+def test_lazy_register_raising_init():
+    def f():
+        return 3
+
+    def g():
+        return 3
+
+    class LazyRegister(BaseLazyRegistering):
+        def __init__(self):
+            1/0
+
+        @registering(f)
+        def register_f(self):
+            pass
+
+        @registering(g)
+        def register_g(self):
+            pass
+
+    py.test.raises(ZeroDivisionError, interpret, lambda : f(), [])
+    py.test.raises(ZeroDivisionError, interpret, lambda : g(), [])
+    



More information about the Pypy-commit mailing list