Author: Armin Rigo <ar...@tunes.org>
Branch: cffi-static-callback-embedding
Changeset: r81507:81e85ede3e5a
Date: 2015-12-30 15:52 +0100
http://bitbucket.org/pypy/pypy/changeset/81e85ede3e5a/

Log:    continue the cffi-static-callback-embedding branch, merge from
        default

diff --git a/pypy/goal/targetpypystandalone.py 
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -10,8 +10,6 @@
 from rpython.config.config import ConflictConfigError
 from pypy.tool.option import make_objspace
 from pypy.conftest import pypydir
-from rpython.rlib import rthread
-from pypy.module.thread import os_thread
 
 thisdir = py.path.local(__file__).dirpath()
 
@@ -78,108 +76,8 @@
                 return 1
         return exitcode
 
-    # register the minimal equivalent of running a small piece of code. This
-    # should be used as sparsely as possible, just to register callbacks
-
-    from rpython.rlib.entrypoint import entrypoint_highlevel
-    from rpython.rtyper.lltypesystem import rffi, lltype
-
-    w_pathsetter = space.appexec([], """():
-    def f(path):
-        import sys
-        sys.path[:] = path
-    return f
-    """)
-
-    @entrypoint_highlevel('main', [rffi.CCHARP, rffi.INT],
-                          c_name='pypy_setup_home')
-    def pypy_setup_home(ll_home, verbose):
-        from pypy.module.sys.initpath import pypy_find_stdlib
-        verbose = rffi.cast(lltype.Signed, verbose)
-        if ll_home:
-            home1 = rffi.charp2str(ll_home)
-            home = os.path.join(home1, 'x') # <- so that 'll_home' can be
-                                            # directly the root directory
-        else:
-            home = home1 = pypydir
-        w_path = pypy_find_stdlib(space, home)
-        if space.is_none(w_path):
-            if verbose:
-                debug("pypy_setup_home: directories 'lib-python' and 
'lib_pypy'"
-                      " not found in '%s' or in any parent directory" % home1)
-            return rffi.cast(rffi.INT, 1)
-        space.startup()
-        space.call_function(w_pathsetter, w_path)
-        # import site
-        try:
-            space.setattr(space.getbuiltinmodule('sys'),
-                          space.wrap('executable'),
-                          space.wrap(home))
-            import_ = space.getattr(space.getbuiltinmodule('__builtin__'),
-                                    space.wrap('__import__'))
-            space.call_function(import_, space.wrap('site'))
-            return rffi.cast(rffi.INT, 0)
-        except OperationError, e:
-            if verbose:
-                debug("OperationError:")
-                debug(" operror-type: " + e.w_type.getname(space))
-                debug(" operror-value: " + 
space.str_w(space.str(e.get_w_value(space))))
-            return rffi.cast(rffi.INT, -1)
-
-    @entrypoint_highlevel('main', [rffi.CCHARP], c_name='pypy_execute_source')
-    def pypy_execute_source(ll_source):
-        return pypy_execute_source_ptr(ll_source, 0)
-
-    @entrypoint_highlevel('main', [rffi.CCHARP, lltype.Signed],
-                          c_name='pypy_execute_source_ptr')
-    def pypy_execute_source_ptr(ll_source, ll_ptr):
-        source = rffi.charp2str(ll_source)
-        res = _pypy_execute_source(source, ll_ptr)
-        return rffi.cast(rffi.INT, res)
-
-    @entrypoint_highlevel('main', [], c_name='pypy_init_threads')
-    def pypy_init_threads():
-        if not space.config.objspace.usemodules.thread:
-            return
-        os_thread.setup_threads(space)
-
-    @entrypoint_highlevel('main', [], c_name='pypy_thread_attach')
-    def pypy_thread_attach():
-        if not space.config.objspace.usemodules.thread:
-            return
-        os_thread.setup_threads(space)
-        os_thread.bootstrapper.acquire(space, None, None)
-        rthread.gc_thread_start()
-        os_thread.bootstrapper.nbthreads += 1
-        os_thread.bootstrapper.release()
-
-    def _pypy_execute_source(source, c_argument):
-        try:
-            w_globals = space.newdict(module=True)
-            space.setitem(w_globals, space.wrap('__builtins__'),
-                          space.builtin_modules['__builtin__'])
-            space.setitem(w_globals, space.wrap('c_argument'),
-                          space.wrap(c_argument))
-            space.appexec([space.wrap(source), w_globals], """(src, glob):
-                import sys
-                stmt = compile(src, 'c callback', 'exec')
-                if not hasattr(sys, '_pypy_execute_source'):
-                    sys._pypy_execute_source = []
-                sys._pypy_execute_source.append(glob)
-                exec stmt in glob
-            """)
-        except OperationError, e:
-            debug("OperationError:")
-            debug(" operror-type: " + e.w_type.getname(space))
-            debug(" operror-value: " + 
space.str_w(space.str(e.get_w_value(space))))
-            return -1
-        return 0
-
-    return entry_point, {'pypy_execute_source': pypy_execute_source,
-                         'pypy_execute_source_ptr': pypy_execute_source_ptr,
-                         'pypy_init_threads': pypy_init_threads,
-                         'pypy_thread_attach': pypy_thread_attach,
-                         'pypy_setup_home': pypy_setup_home}
+    from pypy.interpreter import embedding
+    return entry_point, embedding.capture(space, debug)
 
 
 # _____ Define and setup target ___
diff --git a/pypy/interpreter/embedding.py b/pypy/interpreter/embedding.py
new file mode 100644
--- /dev/null
+++ b/pypy/interpreter/embedding.py
@@ -0,0 +1,173 @@
+from rpython.rtyper.lltypesystem import rffi, lltype
+
+
+def capture(space, debug):
+    from rpython.rlib.entrypoint import entrypoint_highlevel
+    from rpython.rlib import rthread
+    from pypy.module.thread import os_thread
+    from pypy.conftest import pypydir
+    from pypy.module.sys.initpath import pypy_find_stdlib
+
+    @entrypoint_highlevel('main', [rffi.CCHARP, rffi.INT],
+                          c_name='pypy_setup_home')
+    def pypy_setup_home(ll_home, verbose):
+        _declare_c_function()
+        verbose = rffi.cast(lltype.Signed, verbose)
+        if ll_home:
+            home1 = rffi.charp2str(ll_home)
+            home = os.path.join(home1, 'x') # <- so that 'll_home' can be
+                                            # directly the root directory
+        else:
+            home = home1 = pypydir
+        w_path = pypy_find_stdlib(space, home)
+        if space.is_none(w_path):
+            if verbose:
+                debug("pypy_setup_home: directories 'lib-python' and 
'lib_pypy'"
+                      " not found in '%s' or in any parent directory" % home1)
+            return rffi.cast(rffi.INT, 1)
+        space.startup()
+        space.appexec([w_path], """(path):
+            import sys
+            sys.path[:] = path
+        """)
+        # import site
+        try:
+            space.setattr(space.getbuiltinmodule('sys'),
+                          space.wrap('executable'),
+                          space.wrap(home))
+            import_ = space.getattr(space.getbuiltinmodule('__builtin__'),
+                                    space.wrap('__import__'))
+            space.call_function(import_, space.wrap('site'))
+            return rffi.cast(rffi.INT, 0)
+        except OperationError, e:
+            if verbose:
+                debug("OperationError:")
+                debug(" operror-type: " + e.w_type.getname(space))
+                debug(" operror-value: " + 
space.str_w(space.str(e.get_w_value(space))))
+            return rffi.cast(rffi.INT, -1)
+
+    @entrypoint_highlevel('main', [rffi.CCHARP], c_name='pypy_execute_source')
+    def pypy_execute_source(ll_source):
+        return pypy_execute_source_ptr(ll_source, 0)
+
+    @entrypoint_highlevel('main', [rffi.CCHARP, lltype.Signed],
+                          c_name='pypy_execute_source_ptr')
+    def pypy_execute_source_ptr(ll_source, ll_ptr):
+        source = rffi.charp2str(ll_source)
+        res = _pypy_execute_source(source, ll_ptr)
+        return rffi.cast(rffi.INT, res)
+
+    @entrypoint_highlevel('main', [], c_name='pypy_init_threads')
+    def pypy_init_threads():
+        if not space.config.objspace.usemodules.thread:
+            return
+        os_thread.setup_threads(space)
+
+    @entrypoint_highlevel('main', [], c_name='pypy_thread_attach')
+    def pypy_thread_attach():
+        if not space.config.objspace.usemodules.thread:
+            return
+        # XXX this doesn't really work.  Don't use os.fork(), and
+        # if your embedder program uses fork(), don't use any PyPy
+        # code in the fork
+        rthread.gc_thread_start()
+        os_thread.bootstrapper.nbthreads += 1
+
+    def _pypy_execute_source(source, c_argument):
+        try:
+            w_globals = space.newdict(module=True)
+            space.setitem(w_globals, space.wrap('__builtins__'),
+                          space.builtin_modules['__builtin__'])
+            space.setitem(w_globals, space.wrap('c_argument'),
+                          space.wrap(c_argument))
+            space.appexec([space.wrap(source), w_globals], """(src, glob):
+                import sys
+                stmt = compile(src, 'c callback', 'exec')
+                if not hasattr(sys, '_pypy_execute_source'):
+                    sys._pypy_execute_source = []
+                sys._pypy_execute_source.append(glob)
+                exec stmt in glob
+            """)
+        except OperationError, e:
+            debug("OperationError:")
+            debug(" operror-type: " + e.w_type.getname(space))
+            debug(" operror-value: " + 
space.str_w(space.str(e.get_w_value(space))))
+            return -1
+        return 0
+
+    entrypoints_dict = {'pypy_execute_source': pypy_execute_source,
+                        'pypy_execute_source_ptr': pypy_execute_source_ptr,
+                        'pypy_init_threads': pypy_init_threads,
+                        'pypy_thread_attach': pypy_thread_attach,
+                        'pypy_setup_home': pypy_setup_home}
+
+    return entrypoints_dict
+
+
+_declare_c_function = rffi.llexternal_use_eci(separate_module_sources=[
+"""
+#define PYPY_INIT_NO_THREADS   0x01
+#define PYPY_INIT_QUIET        0x02
+
+static char _pypy_init_ok = 0;
+static void _pypy_init_once_quiet(void);
+static void _pypy_init_once_verbose(void);
+
+
+#ifndef _MSC_VER   /* --- Posix version --- */
+
+static char *guess_home(void)
+{
+    Dl_info info;
+    if (dladdr(&guess_home, &info) == 0)
+        return NULL;
+    return realpath(info.dli_fname, NULL);
+}
+
+RPY_EXPORTED
+int pypy_initialize(int flags)
+{
+    static pthread_once_t once_control_1 = PTHREAD_ONCE_INIT;
+    static pthread_once_t once_control_2 = PTHREAD_ONCE_INIT;
+
+    pthread_once(&once_control_1,
+                 (flags & PYPY_INIT_QUIET) ? _pypy_init_once_quiet
+                                           : _pypy_init_once_verbose);
+
+    if (_pypy_init_ok && (flags & PYPY_INIT_NO_THREADS) == 0)
+        pthread_once(&once_control_2, pypy_init_threads);
+
+    return _pypy_init_ok ? 0 : -1;
+}
+
+#else            /* --- Windows version --- */
+
+   XXX
+
+#endif
+
+
+static void _pypy_init_once(int verbose)
+{
+    char *home;
+    int verbose;
+    rpython_startup_code();
+
+    home = guess_home();
+    if (home == NULL)
+        return;
+    _pypy_init_ok = !pypy_setup_home(home, verbose);
+    free(home);
+}
+
+static void _pypy_init_once_quiet(void)
+{
+    _pypy_init_once(0);
+}
+
+static void _pypy_init_once_verbose(void)
+{
+    _pypy_init_once(1);
+}
+"""
+])
diff --git a/pypy/module/_cffi_backend/__init__.py 
b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -65,6 +65,11 @@
     if has_stdcall:
         interpleveldefs['FFI_STDCALL'] = 'space.wrap(%d)' % FFI_STDCALL
 
+    def startup(self, space):
+        from pypy.module._cffi_backend import cffi1_module
+        cffi1_module.glob.space = space
+        cffi1_module.declare_c_function()
+
 
 def get_dict_rtld_constants():
     found = {}
diff --git a/pypy/module/_cffi_backend/cffi1_module.py 
b/pypy/module/_cffi_backend/cffi1_module.py
--- a/pypy/module/_cffi_backend/cffi1_module.py
+++ b/pypy/module/_cffi_backend/cffi1_module.py
@@ -1,6 +1,7 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rlib.entrypoint import entrypoint
 
-from pypy.interpreter.error import oefmt
+from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.module import Module
 from pypy.module._cffi_backend import parse_c_type
 from pypy.module._cffi_backend.ffi_obj import W_FFIObject
@@ -12,14 +13,14 @@
 
 VERSION_EXPORT = 0x0A03
 
-initfunctype = lltype.Ptr(lltype.FuncType([rffi.VOIDPP], lltype.Void))
+INITFUNCPTR = lltype.Ptr(lltype.FuncType([rffi.VOIDPP], lltype.Void))
 
 
 def load_cffi1_module(space, name, path, initptr):
     # This is called from pypy.module.cpyext.api.load_extension_module()
     from pypy.module._cffi_backend.call_python import get_ll_cffi_call_python
 
-    initfunc = rffi.cast(initfunctype, initptr)
+    initfunc = rffi.cast(INITFUNCPTR, initptr)
     with lltype.scoped_alloc(rffi.VOIDPP.TO, 16, zero=True) as p:
         p[0] = rffi.cast(rffi.VOIDP, VERSION_EXPORT)
         p[1] = rffi.cast(rffi.VOIDP, get_ll_cffi_call_python())
@@ -38,9 +39,74 @@
 
     w_name = space.wrap(name)
     module = Module(space, w_name)
-    module.setdictvalue(space, '__file__', space.wrap(path))
+    if path is not None:
+        module.setdictvalue(space, '__file__', space.wrap(path))
     module.setdictvalue(space, 'ffi', space.wrap(ffi))
     module.setdictvalue(space, 'lib', space.wrap(lib))
     w_modules_dict = space.sys.get('modules')
     space.setitem(w_modules_dict, w_name, space.wrap(module))
     space.setitem(w_modules_dict, space.wrap(name + '.lib'), space.wrap(lib))
+    return module
+
+
+# ____________________________________________________________
+
+
+EMBED_VERSION_MIN    = 0xB011
+EMBED_VERSION_MAX    = 0xB0FF
+
+STDERR = 2
+INITSTRUCTPTR = lltype.Ptr(lltype.Struct('CFFI_INIT',
+                                         ('name', rffi.CCHARP),
+                                         ('func', rffi.VOIDP),
+                                         ('code', rffi.CCHARP)))
+
+def load_embedded_cffi_module(space, version, init_struct):
+    name = rffi.charp2str(init_struct.name)
+    if not (VERSION_MIN <= version <= VERSION_MAX):
+        raise oefmt(space.w_ImportError,
+            "cffi *embedded* module '%s' has unknown version %s",
+            name, hex(version))
+    module = load_cffi1_module(space, name, None, init_struct.func)
+    #
+    code = rffi.charp2str(init_struct.code)
+    compiler = space.createcompiler()
+    pycode = compiler.compile(code, "<init code for '%s'>" % name,
+                              'exec', 0)
+    w_globals = module.getdict(space)
+    space.call_method(w_globals, "setdefault", "__builtins__",
+                      self.get_builtin())
+    pycode.exec_code(self, w_globals, w_globals)
+
+
+class Global:
+    pass
+glob = Global()
+
+@entrypoint('main', [rffi.INT, rffi.VOIDP],
+            c_name='_pypy_init_embedded_cffi_module')
+def _pypy_init_embedded_cffi_module(version, init_struct):
+    name = "?"
+    try:
+        init_struct = rffi.cast(INITSTRUCTPTR, init_struct)
+        name = rffi.charp2str(init_struct.name)
+        version = rffi.cast(lltype.Signed, version)
+        try:
+            load_embedded_cffi_module(glob.space, version, init_struct)
+            res = 0
+        except OperationError, operr:
+            operr.write_unraisable(glob.space, "initialization of '%s'" % name,
+                                   with_traceback=True)
+            res = -1
+    except Exception, e:
+        # oups! last-level attempt to recover.
+        try:
+            os.write(STDERR, "From initialization of '")
+            os.write(STDERR, name)
+            os.write(STDERR, "':\n")
+            os.write(STDERR, str(e))
+            os.write(STDERR, "\n")
+        except:
+            pass
+        res = -1
+    return rffi.cast(rffi.INT, res)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to