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