Skip to content

Instantly share code, notes, and snippets.

@dutc
Last active September 2, 2021 23:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dutc/eba9b2f7980f400f6287 to your computer and use it in GitHub Desktop.
Save dutc/eba9b2f7980f400f6287 to your computer and use it in GitHub Desktop.
cffi version of dlmopen CPython embedding
#!/usr/bin/python
from cffi import FFI
from textwrap import dedent
from sys import exit
if __name__ == '__main__':
ffi = FFI()
ffi.cdef('''
void *dlmopen (long int __nsid, const char*, int);
void *dlopen (const char*, int);
void *dlsym(void *handle, const char *symbol);
char *dlerror(void);
''')
LM_ID_NEWLM = -1
libc = ffi.dlopen('libdl.so.2')
# clear error
libc.dlerror()
handle = libc.dlmopen(LM_ID_NEWLM, 'libpython2.7.so', ffi.RTLD_DEEPBIND | ffi.RTLD_LOCAL | ffi.RTLD_LAZY)
#handle = libc.dlopen('libpython2.7.so', ffi.RTLD_DEEPBIND | ffi.RTLD_LOCAL | ffi.RTLD_LAZY)
error = libc.dlerror()
if error:
print('error: {}'.format(ffi.string(error)))
exit(1)
init = ffi.cast('void (*)(void)', libc.dlsym(handle, 'Py_Initialize'))
error = libc.dlerror()
if error:
print('error: {}'.format(ffi.string(error)))
exit(1)
fini = ffi.cast('void (*)(void)', libc.dlsym(handle, 'Py_Finalize'))
error = libc.dlerror()
if error:
print('error: {}'.format(ffi.string(error)))
exit(1)
run = ffi.cast('void (*)(const char*)', libc.dlsym(handle, 'PyRun_SimpleString'))
error = libc.dlerror()
if error:
print('error: {}'.format(ffi.string(error)))
exit(1)
init()
cmd = dedent('''
from sys import version_info
from os import getpid
print('Version info: {}'.format(version_info))
print('Process ID: {}'.format(getpid()))
# two quick&dirty tests to check if we're looking at separate interpreterss
# (locale is not thread-safe)
from locale import getlocale, setlocale, LC_ALL
print('Before: {}'.format(getlocale()))
setlocale(LC_ALL, '')
print('After: {}'.format(getlocale()))
# interpreter-level state
from sys import modules
print('Before: {}'.format('itertools' in modules))
from itertools import chain
print('After: {}'.format('itertools' in modules))
print('\\n')
execfile('cffi-test.py')''')
run(cmd)
fini()
@eric-saintetienne
Copy link

This works, but have you tried to run python interpreters inside threads?

I'm trying to use separate interpreters from Go routines where each interpreter is pinned to its own OS thread.
Despite dlmopen() namespace support, this approach fails for more than two concurrent python interpreters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment