Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit