[pypy-commit] cffi cffi-1.0: in-progress: ffi.dlopen()
arigo
noreply at buildbot.pypy.org
Mon May 11 17:24:05 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1972:2148820bd1cb
Date: 2015-05-11 13:36 +0200
http://bitbucket.org/cffi/cffi/changeset/2148820bd1cb/
Log: in-progress: ffi.dlopen()
diff --git a/_cffi1/cdlopen.c b/_cffi1/cdlopen.c
new file mode 100644
--- /dev/null
+++ b/_cffi1/cdlopen.c
@@ -0,0 +1,57 @@
+/* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */
+
+static void *cdlopen_fetch(PyObject *libname, void *libhandle, char *symbol)
+{
+ void *address;
+
+ if (libhandle == NULL) {
+ PyErr_Format(FFIError, "library '%s' has been closed",
+ PyText_AS_UTF8(libname));
+ return NULL;
+ }
+
+ address = dlsym(libhandle, symbol);
+ if (address == NULL) {
+ const char *error = dlerror();
+ PyErr_Format(FFIError, "symbol '%s' not found in library '%s': %s",
+ symbol, PyText_AS_UTF8(libname), error);
+ }
+ return address;
+}
+
+static int cdlopen_close(PyObject *libname, void *libhandle)
+{
+ if (libhandle != NULL && dlclose(libhandle) != 0) {
+ const char *error = dlerror();
+ PyErr_Format(FFIError, "closing library '%s': %s",
+ PyText_AS_UTF8(libname), error);
+ return -1;
+ }
+ return 0;
+}
+
+
+
+static PyObject *ffi_dlclose(PyObject *self, PyObject *args)
+{
+ LibObject *lib;
+ if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib))
+ return NULL;
+
+ if (lib->l_libhandle == NULL) {
+ PyErr_Format(FFIError, "library '%s' is already closed "
+ "or was not created with ffi.dlopen()",
+ PyText_AS_UTF8(lib->l_libhandle));
+ return NULL;
+ }
+
+ if (cdlopen_close(lib->l_libname, lib->l_libhandle) < 0)
+ return NULL;
+
+ /* Clear the dict to force further accesses to do cdlopen_fetch()
+ again, and fail because the library was closed. */
+ PyDict_Clear(lib->l_dict);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
diff --git a/_cffi1/cffi1_module.c b/_cffi1/cffi1_module.c
--- a/_cffi1/cffi1_module.c
+++ b/_cffi1/cffi1_module.c
@@ -12,6 +12,7 @@
#include "cglob.c"
#include "cgc.c"
#include "lib_obj.c"
+#include "cdlopen.c"
static int init_ffi_lib(PyObject *m)
@@ -169,7 +170,7 @@
if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
return NULL;
- lib = lib_internal_new(ffi, module_name);
+ lib = lib_internal_new(ffi, module_name, NULL);
if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0)
return NULL;
diff --git a/_cffi1/cffi_opcode.py b/_cffi1/cffi_opcode.py
--- a/_cffi1/cffi_opcode.py
+++ b/_cffi1/cffi_opcode.py
@@ -30,6 +30,7 @@
OP_CONSTANT = 29
OP_CONSTANT_INT = 31
OP_GLOBAL_VAR = 33
+OP_DLOPEN = 35
PRIM_VOID = 0
PRIM_BOOL = 1
diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c
--- a/_cffi1/ffi_obj.c
+++ b/_cffi1/ffi_obj.c
@@ -24,7 +24,7 @@
PyObject_HEAD
PyObject *gc_wrefs;
struct _cffi_parse_info_s info;
- int ctx_is_static;
+ char ctx_is_static, ctx_is_nonempty;
builder_c_t types_builder;
};
@@ -54,9 +54,7 @@
ffi->info.output = internal_output;
ffi->info.output_size = FFI_COMPLEXITY_OUTPUT;
ffi->ctx_is_static = (static_ctx != NULL);
-#if 0
- ffi->dynamic_types = NULL;
-#endif
+ ffi->ctx_is_nonempty = (static_ctx != NULL);
return ffi;
}
@@ -64,12 +62,8 @@
{
PyObject_GC_UnTrack(ffi);
Py_XDECREF(ffi->gc_wrefs);
-#if 0
- Py_XDECREF(ffi->dynamic_types);
-#endif
- if (!ffi->ctx_is_static)
- free_dynamic_builder_c(&ffi->types_builder);
+ free_builder_c(&ffi->types_builder, ffi->ctx_is_static);
Py_TYPE(ffi)->tp_free((PyObject *)ffi);
}
@@ -90,9 +84,31 @@
static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *keywords[] = {NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, ":FFI", keywords))
+ FFIObject *ffi;
+ static char *keywords[] = {"module_name", "_version", "_types",
+ "_globals", "_struct_unions", "_enums",
+ "_typenames", "_consts", NULL};
+ char *ffiname = NULL, *types = NULL;
+ Py_ssize_t version = -1;
+ Py_ssize_t types_len = 0;
+ PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL;
+ PyObject *typenames = NULL, *consts = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sns#OOOOO:FFI", keywords,
+ &ffiname, &version, &types, &types_len,
+ &globals, &struct_unions, &enums,
+ &typenames, &consts))
return -1;
+
+ ffi = (FFIObject *)self;
+ if (ffi->ctx_is_nonempty) {
+ PyErr_SetString(PyExc_ValueError,
+ "cannot call FFI.__init__() more than once");
+ return -1;
+ }
+
+ //...;
+ ffi->ctx_is_nonempty = 1;
return 0;
}
@@ -671,6 +687,23 @@
return 0;
}
+PyDoc_STRVAR(ffi_dlopen_doc,
+"Load and return a dynamic library identified by 'name'. The standard\n"
+"C library can be loaded by passing None.\n"
+"\n"
+"Note that functions and types declared with 'ffi.cdef()' are not\n"
+"linked to a particular library, just like C headers. In the library\n"
+"we only look for the actual (untyped) symbols at the time of their\n"
+"first access.");
+
+PyDoc_STRVAR(ffi_dlclose_doc,
+"Close a library obtained with ffi.dlopen(). After this call, access to\n"
+"functions or variables from the library will fail (possibly with a\n"
+"segmentation fault).");
+
+static PyObject *ffi_dlopen(PyObject *self, PyObject *args); /* forward */
+static PyObject *ffi_dlclose(PyObject *self, PyObject *args); /* forward */
+
#if 0
static PyObject *ffi__set_types(FFIObject *self, PyObject *args)
{
@@ -767,6 +800,8 @@
{"buffer", (PyCFunction)ffi_buffer, METH_VARARGS, ffi_buffer_doc},
{"callback", (PyCFunction)ffi_callback, METH_VKW, ffi_callback_doc},
{"cast", (PyCFunction)ffi_cast, METH_VARARGS, ffi_cast_doc},
+ {"dlclose", (PyCFunction)ffi_dlclose, METH_VARARGS, ffi_dlclose_doc},
+ {"dlopen", (PyCFunction)ffi_dlopen, METH_VARARGS, ffi_dlopen_doc},
{"from_buffer",(PyCFunction)ffi_from_buffer,METH_O, ffi_from_buffer_doc},
{"from_handle",(PyCFunction)ffi_from_handle,METH_O, ffi_from_handle_doc},
{"gc", (PyCFunction)ffi_gc, METH_VKW, ffi_gc_doc},
diff --git a/_cffi1/lib_obj.c b/_cffi1/lib_obj.c
--- a/_cffi1/lib_obj.c
+++ b/_cffi1/lib_obj.c
@@ -25,6 +25,7 @@
PyObject *l_libname; /* some string that gives the name of the lib */
PyObject *l_includes; /* tuple of LibObjects included here */
FFIObject *l_ffi; /* reference back to the ffi object */
+ void *l_libhandle; /* the dlopen()ed handle, if any */
};
#define LibObject_Check(ob) ((Py_TYPE(ob) == &Lib_Type))
@@ -63,8 +64,15 @@
return result;
}
+static int cdlopen_close(PyObject *libname, void *libhandle); /* forward */
+static void *cdlopen_fetch(PyObject *libname, void *libhandle, char *symbol);
+
static void lib_dealloc(LibObject *lib)
{
+ if (cdlopen_close(lib->l_libname, lib->l_libhandle) < 0) {
+ PyErr_WriteUnraisable((PyObject *)lib);
+ PyErr_Clear();
+ }
Py_DECREF(lib->l_dict);
Py_DECREF(lib->l_libname);
Py_XDECREF(lib->l_includes);
@@ -153,6 +161,14 @@
index = search_in_globals(&lib->l_types_builder->ctx, s, strlen(s));
if (index < 0) {
+ if (lib->l_types_builder->known_constants != NULL) {
+ x = PyDict_GetItem(lib->l_types_builder->known_constants, name);
+ if (x != NULL) {
+ Py_INCREF(x);
+ goto found;
+ }
+ }
+
if (lib->l_includes != NULL) {
Py_ssize_t i;
@@ -253,6 +269,36 @@
Py_DECREF(ct);
break;
+ case _CFFI_OP_DLOPEN:
+ {
+ /* For dlopen(): the function or global variable of the given
+ 'name'. We use dlsym() to get the address of something in
+ the dynamic library, which we interpret as being exactly of
+ the specified type. If this type is a function (not a
+ function pointer), then we assume it is a regular function
+ in the dynamic library; otherwise, we assume it is a global
+ variable.
+ */
+ PyObject *ct1;
+ void *address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s);
+ if (address == NULL)
+ return NULL;
+
+ ct1 = realize_c_type_or_func(lib->l_types_builder,
+ lib->l_types_builder->ctx.types,
+ _CFFI_GETARG(g->type_op));
+ if (ct1 == NULL)
+ return NULL;
+
+ if (CTypeDescr_Check(ct1))
+ x = make_global_var((CTypeDescrObject *)ct1, address);
+ else
+ x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1));
+
+ Py_DECREF(ct1);
+ break;
+ }
+
default:
PyErr_Format(PyExc_NotImplementedError, "in lib_build_attr: op=%d",
(int)_CFFI_GETOP(g->type_op));
@@ -371,7 +417,8 @@
offsetof(LibObject, l_dict), /* tp_dictoffset */
};
-static LibObject *lib_internal_new(FFIObject *ffi, char *module_name)
+static LibObject *lib_internal_new(FFIObject *ffi, char *module_name,
+ void *dlopen_libhandle)
{
LibObject *lib;
PyObject *libname, *dict;
@@ -394,5 +441,6 @@
lib->l_includes = NULL;
Py_INCREF(ffi);
lib->l_ffi = ffi;
+ lib->l_libhandle = dlopen_libhandle;
return lib;
}
diff --git a/_cffi1/parse_c_type.h b/_cffi1/parse_c_type.h
--- a/_cffi1/parse_c_type.h
+++ b/_cffi1/parse_c_type.h
@@ -22,6 +22,7 @@
#define _CFFI_OP_CONSTANT 29
#define _CFFI_OP_CONSTANT_INT 31
#define _CFFI_OP_GLOBAL_VAR 33
+#define _CFFI_OP_DLOPEN 35
#define _CFFI_PRIM_VOID 0
#define _CFFI_PRIM_BOOL 1
diff --git a/_cffi1/realize_c_type.c b/_cffi1/realize_c_type.c
--- a/_cffi1/realize_c_type.c
+++ b/_cffi1/realize_c_type.c
@@ -3,6 +3,7 @@
struct _cffi_type_context_s ctx; /* inlined substructure */
PyObject *types_dict;
PyObject *included_ffis;
+ PyObject *known_constants;
} builder_c_t;
@@ -53,22 +54,24 @@
return err;
}
-static void free_dynamic_builder_c(builder_c_t *builder)
+static void free_builder_c(builder_c_t *builder, int ctx_is_static)
{
- int i;
- const void *mem[] = {builder->ctx.types,
- builder->ctx.globals,
- builder->ctx.struct_unions,
- builder->ctx.fields,
- builder->ctx.enums,
- builder->ctx.typenames};
- for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) {
- if (mem[i] != NULL)
- PyMem_Free((void *)mem[i]);
+ if (!ctx_is_static) {
+ int i;
+ const void *mem[] = {builder->ctx.types,
+ builder->ctx.globals,
+ builder->ctx.struct_unions,
+ builder->ctx.fields,
+ builder->ctx.enums,
+ builder->ctx.typenames};
+ for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) {
+ if (mem[i] != NULL)
+ PyMem_Free((void *)mem[i]);
+ }
}
-
Py_XDECREF(builder->included_ffis);
Py_XDECREF(builder->types_dict);
+ Py_XDECREF(builder->known_constants);
}
static int init_builder_c(builder_c_t *builder,
@@ -85,6 +88,7 @@
builder->types_dict = ldict;
builder->included_ffis = NULL;
+ builder->known_constants = NULL;
return 0;
}
More information about the pypy-commit
mailing list