[pypy-commit] cffi cffi-1.0: in-progress: loading C extension modules and calling functions from them
arigo
noreply at buildbot.pypy.org
Tue Apr 14 17:28:48 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1704:102edaf76b7c
Date: 2015-04-14 17:29 +0200
http://bitbucket.org/cffi/cffi/changeset/102edaf76b7c/
Log: in-progress: loading C extension modules and calling functions from
them
diff --git a/new/cffi1_module.c b/new/cffi1_module.c
--- a/new/cffi1_module.c
+++ b/new/cffi1_module.c
@@ -10,7 +10,7 @@
static PyObject *FFIError;
#include "ffi_obj.c"
-//#include "lib_obj.c"
+#include "lib_obj.c"
static int init_ffi_lib(PyObject *m)
@@ -32,6 +32,9 @@
Py_INCREF(&FFI_Type);
if (PyModule_AddObject(m, "FFI", (PyObject *)&FFI_Type) < 0)
return -1;
+ Py_INCREF(&Lib_Type);
+ if (PyModule_AddObject(m, "Lib", (PyObject *)&Lib_Type) < 0)
+ return -1;
return 0;
}
@@ -47,5 +50,9 @@
if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
return -1;
+ LibObject *lib = lib_internal_new(ctx, module_name);
+ if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0)
+ return -1;
+
return 0;
}
diff --git a/new/lib_obj.c b/new/lib_obj.c
--- a/new/lib_obj.c
+++ b/new/lib_obj.c
@@ -12,69 +12,143 @@
__getattr__ which returns C globals, functions and constants. It
raises AttributeError for anything else, like '__class__'.
- A Lib object has internally a reference back to the FFI object,
- which holds the _cffi_type_context_s used to create lazily the
- objects returned by __getattr__. For a dlopen()ed Lib object, all
- the 'address' fields in _cffi_global_s are NULL, and instead
- dlsym() is used lazily on the l_dl_lib.
+ A Lib object has got a reference to the _cffi_type_context_s
+ structure, which is used to create lazily the objects returned by
+ __getattr__. For a dlopen()ed Lib object, all the 'address' fields
+ in _cffi_global_s are NULL, and instead dlsym() is used lazily on
+ the l_dl_lib.
*/
+struct CPyExtFunc_s {
+ PyMethodDef md;
+ const struct _cffi_type_context_s *ctx;
+ int type_index;
+};
+
struct LibObject_s {
PyObject_HEAD
+ const struct _cffi_type_context_s *l_ctx; /* ctx object */
PyObject *l_dict; /* content, built lazily */
- struct FFIObject_s *l_ffi; /* ffi object */
void *l_dl_lib; /* the result of 'dlopen()', or NULL */
+ PyObject *l_libname; /* some string that gives the name of the lib */
};
-#define ZefLib_Check(ob) ((Py_TYPE(ob) == &ZefLib_Type))
+#define LibObject_Check(ob) ((Py_TYPE(ob) == &Lib_Type))
-static void lib_dealloc(ZefLibObject *lib)
+static int lib_close(LibObject *lib); /* forward */
+
+static void lib_dealloc(LibObject *lib)
{
(void)lib_close(lib);
+ Py_DECREF(lib->l_dict);
+ Py_DECREF(lib->l_libname);
PyObject_Del(lib);
}
-static PyObject *lib_repr(ZefLibObject *lib)
+static PyObject *lib_repr(LibObject *lib)
{
- return PyText_FromFormat("<zeffir.Lib object for '%.200s'%s>",
- lib->l_libname,
- lib->l_dl_lib == NULL ? " (closed)" : "");
+ return PyText_FromFormat("<cffi.Lib object for '%.200s'>",
+ PyText_AS_UTF8(lib->l_libname));
}
-static PyObject *lib_findattr(ZefLibObject *lib, PyObject *name, PyObject *exc)
+static PyObject *lib_build_cpython_func(LibObject *lib,
+ const struct _cffi_global_s *g,
+ const char *s, int flags)
+{
+ /* xxx the few bytes of memory we allocate here leak, but it's a
+ minor concern because it should only occur for CPYTHON_BLTN.
+ There is one per real C function in a CFFI C extension module.
+ CPython never unloads its C extension modules anyway.
+ */
+ struct CPyExtFunc_s *xfunc = calloc(1, sizeof(struct CPyExtFunc_s));
+ if (xfunc == NULL)
+ goto no_memory;
+
+ xfunc->md.ml_meth = (PyCFunction)g->address;
+ xfunc->md.ml_flags = flags;
+ xfunc->md.ml_name = strdup(s);
+ /*xfunc->md.ml_doc = ... */
+ if (xfunc->md.ml_name == NULL)
+ goto no_memory;
+
+ xfunc->ctx = lib->l_ctx;
+ xfunc->type_index = _CFFI_GETARG(g->type_op);
+
+ return PyCFunction_NewEx(&xfunc->md, NULL, lib->l_libname);
+
+ no_memory:
+ PyErr_NoMemory();
+ return NULL;
+}
+
+static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name)
{
/* does not return a new reference! */
- if (lib->l_dict == NULL) {
- PyErr_Format(ZefError, "lib '%.200s' was closed", lib->l_libname);
+ if (lib->l_ctx == NULL) {
+ PyErr_Format(FFIError, "lib '%.200s' is already closed",
+ PyText_AS_UTF8(lib->l_libname));
return NULL;
}
- PyObject *x = PyDict_GetItem(lib->l_dict, name);
- if (x == NULL) {
- PyErr_Format(exc,
+ char *s = PyText_AsUTF8(name);
+ if (s == NULL)
+ return NULL;
+
+ int index = search_in_globals(lib->l_ctx, s, strlen(s));
+ if (index < 0) {
+ PyErr_Format(PyExc_AttributeError,
"lib '%.200s' has no function,"
- " global variable or constant '%.200s'",
- lib->l_libname,
+ " global variable or constant named '%.200s'",
+ PyText_AS_UTF8(lib->l_libname),
PyText_Check(name) ? PyText_AS_UTF8(name) : "?");
return NULL;
}
+
+ const struct _cffi_global_s *g = &lib->l_ctx->globals[index];
+ PyObject *x;
+
+ switch (_CFFI_GETOP(g->type_op)) {
+
+ case _CFFI_OP_CPYTHON_BLTN_V:
+ x = lib_build_cpython_func(lib, g, s, METH_VARARGS);
+ break;
+
+ case _CFFI_OP_CPYTHON_BLTN_N:
+ x = lib_build_cpython_func(lib, g, s, METH_NOARGS);
+ break;
+
+ case _CFFI_OP_CPYTHON_BLTN_O:
+ x = lib_build_cpython_func(lib, g, s, METH_O);
+ break;
+
+ default:
+ PyErr_SetString(PyExc_NotImplementedError, "in lib_build_attr");
+ return NULL;
+ }
+
+ if (x != NULL) {
+ int err = PyDict_SetItem(lib->l_dict, name, x);
+ Py_DECREF(x);
+ if (err < 0) /* else there is still one ref left in the dict */
+ return NULL;
+ }
return x;
}
-static PyObject *lib_getattr(ZefLibObject *lib, PyObject *name)
+static PyObject *lib_getattr(LibObject *lib, PyObject *name)
{
- PyObject *x = lib_findattr(lib, name, PyExc_AttributeError);
+ PyObject *x = PyDict_GetItem(lib->l_dict, name);
if (x == NULL)
- return NULL;
+ x = lib_build_and_cache_attr(lib, name);
- if (ZefGlobSupport_Check(x)) {
- return read_global_var((ZefGlobSupportObject *)x);
- }
- Py_INCREF(x);
+ //if (ZefGlobSupport_Check(x)) {
+ // return read_global_var((ZefGlobSupportObject *)x);
+ //}
return x;
}
+#if 0
static int lib_setattr(ZefLibObject *lib, PyObject *name, PyObject *val)
{
PyObject *x = lib_findattr(lib, name, PyExc_AttributeError);
@@ -106,11 +180,12 @@
{"__dir__", lib_dir, METH_NOARGS},
{NULL, NULL} /* sentinel */
};
+#endif
-static PyTypeObject ZefLib_Type = {
+static PyTypeObject Lib_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "zeffir.Lib",
- sizeof(ZefLibObject),
+ "cffi.Lib",
+ sizeof(LibObject),
0,
(destructor)lib_dealloc, /* tp_dealloc */
0, /* tp_print */
@@ -125,7 +200,11 @@
0, /* tp_call */
0, /* tp_str */
(getattrofunc)lib_getattr, /* tp_getattro */
+#if 0 // XXX
(setattrofunc)lib_setattr, /* tp_setattro */
+#else
+ 0,
+#endif
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
@@ -135,63 +214,68 @@
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
+#if 0 // XXX
lib_methods, /* tp_methods */
+#else
+ 0,
+#endif
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
- offsetof(ZefLibObject, l_dict), /* tp_dictoffset */
+ offsetof(LibObject, l_dict), /* tp_dictoffset */
};
-static void lib_dlerror(ZefLibObject *lib)
+
+static void lib_dlerror(LibObject *lib)
{
char *error = dlerror();
if (error == NULL)
error = "(no error reported)";
- PyErr_Format(PyExc_OSError, "%s: %s", lib->l_libname, error);
+ PyErr_Format(PyExc_OSError, "%s: %s", PyText_AS_UTF8(lib->l_libname),
+ error);
}
-static ZefLibObject *lib_create(PyObject *path)
+static int lib_close(LibObject *lib)
{
- ZefLibObject *lib;
+ void *dll;
+ lib->l_ctx = NULL;
+ PyDict_Clear(lib->l_dict);
- lib = PyObject_New(ZefLibObject, &ZefLib_Type);
- if (lib == NULL)
- return NULL;
-
- lib->l_dl_lib = NULL;
- lib->l_libname = PyString_AsString(path);
- Py_INCREF(path);
- lib->l_libname_obj = path;
- lib->l_dict = PyDict_New();
- if (lib->l_dict == NULL) {
- Py_DECREF(lib);
- return NULL;
- }
-
- lib->l_dl_lib = dlopen(lib->l_libname, RTLD_LAZY);
- if (lib->l_dl_lib == NULL) {
- lib_dlerror(lib);
- Py_DECREF(lib);
- return NULL;
- }
- return lib;
-}
-
-static int lib_close(ZefLibObject *lib)
-{
- void *dl_lib;
- Py_CLEAR(lib->l_dict);
-
- dl_lib = lib->l_dl_lib;
- if (dl_lib != NULL) {
+ dll = lib->l_dl_lib;
+ if (dll != NULL) {
lib->l_dl_lib = NULL;
- if (dlclose(dl_lib) != 0) {
+ if (dlclose(dll) != 0) {
lib_dlerror(lib);
return -1;
}
}
return 0;
}
+
+static LibObject *lib_internal_new(const struct _cffi_type_context_s *ctx,
+ char *module_name)
+{
+ LibObject *lib;
+ PyObject *libname, *dict;
+
+ libname = PyString_FromString(module_name);
+ dict = PyDict_New();
+ if (libname == NULL || dict == NULL) {
+ Py_XDECREF(dict);
+ Py_XDECREF(libname);
+ return NULL;
+ }
+
+ lib = PyObject_New(LibObject, &Lib_Type);
+ if (lib == NULL)
+ return NULL;
+
+ lib->l_ctx = ctx;
+ lib->l_dict = dict;
+ lib->l_dl_lib = NULL;
+ lib->l_libname = libname;
+ return lib;
+}
diff --git a/new/manual.c b/new/manual.c
--- a/new/manual.c
+++ b/new/manual.c
@@ -80,8 +80,8 @@
}
static const struct _cffi_global_s _cffi_globals[] = {
- { "foo42", &_cffi_f_foo42, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN, 0) },
- { "foo64", &_cffi_f_foo64, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN, 4) },
+ { "foo42", &_cffi_f_foo42, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_V, 0) },
+ { "foo64", &_cffi_f_foo64, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_O, 4) },
};
static const struct _cffi_type_context_s _cffi_type_context = {
@@ -92,7 +92,7 @@
NULL,
NULL,
NULL,
- 1, /* num_globals */
+ 2, /* num_globals */
0,
0,
0,
diff --git a/new/parse_c_type.c b/new/parse_c_type.c
--- a/new/parse_c_type.c
+++ b/new/parse_c_type.c
@@ -349,43 +349,33 @@
return _CFFI_GETARG(result);
}
-static int search_struct_union(const struct _cffi_type_context_s *ctx,
- const char *search, size_t search_len)
-{
- int left = 0, right = ctx->num_structs_unions;
- while (left < right) {
- int middle = (left + right) / 2;
- const char *src = ctx->structs_unions[middle].name;
- int diff = strncmp(src, search, search_len);
- if (diff == 0 && src[search_len] == '\0')
- return middle;
- else if (diff >= 0)
- right = middle;
- else
- left = middle + 1;
- }
- return -1;
-}
+#define MAKE_SEARCH_FUNC(FIELD) \
+ int search_in_##FIELD(const struct _cffi_type_context_s *ctx, \
+ const char *search, size_t search_len) \
+ { \
+ int left = 0, right = ctx->num_##FIELD; \
+ \
+ while (left < right) { \
+ int middle = (left + right) / 2; \
+ const char *src = ctx->FIELD[middle].name; \
+ int diff = strncmp(src, search, search_len); \
+ if (diff == 0 && src[search_len] == '\0') \
+ return middle; \
+ else if (diff >= 0) \
+ right = middle; \
+ else \
+ left = middle + 1; \
+ } \
+ return -1; \
+ }
-static int search_typename(const struct _cffi_type_context_s *ctx,
- const char *search, size_t search_len)
-{
- int left = 0, right = ctx->num_typenames;
+MAKE_SEARCH_FUNC(globals)
+MAKE_SEARCH_FUNC(structs_unions)
+MAKE_SEARCH_FUNC(typenames)
- while (left < right) {
- int middle = (left + right) / 2;
- const char *src = ctx->typenames[middle].name;
- int diff = strncmp(src, search, search_len);
- if (diff == 0 && src[search_len] == '\0')
- return middle;
- else if (diff >= 0)
- right = middle;
- else
- left = middle + 1;
- }
- return -1;
-}
+#undef MAKE_SEARCH_FUNC
+
static int parse_complete(token_t *tok)
{
@@ -512,7 +502,7 @@
break;
case TOK_IDENTIFIER:
{
- int n = search_typename(tok->info->ctx, tok->p, tok->size);
+ int n = search_in_typenames(tok->info->ctx, tok->p, tok->size);
if (n < 0)
return parse_error(tok, "undefined type name");
@@ -527,7 +517,7 @@
if (tok->kind != TOK_IDENTIFIER)
return parse_error(tok, "struct or union name expected");
- int n = search_struct_union(tok->info->ctx, tok->p, tok->size);
+ int n = search_in_structs_unions(tok->info->ctx, tok->p, tok->size);
if (n < 0)
return parse_error(tok, "undefined struct/union name");
if (((tok->info->ctx->structs_unions[n].flags & CT_UNION) != 0)
diff --git a/new/parse_c_type.h b/new/parse_c_type.h
--- a/new/parse_c_type.h
+++ b/new/parse_c_type.h
@@ -18,7 +18,9 @@
#define _CFFI_OP_FUNCTION_END 17
#define _CFFI_OP_NOOP 19
#define _CFFI_OP_BITFIELD 21
-#define _CFFI_OP_CPYTHON_BLTN 23
+#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs
+#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs
+#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg)
#define _CFFI_PRIM_VOID 0
#define _CFFI_PRIM_BOOL 1
@@ -103,3 +105,5 @@
};
int parse_c_type(struct _cffi_parse_info_s *info, const char *input);
+int search_in_globals(const struct _cffi_type_context_s *ctx,
+ const char *search, size_t search_len);
More information about the pypy-commit
mailing list