Author: Armin Rigo <ar...@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); _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit