[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