[pypy-commit] cffi default: Split this test in two.
Author: Armin Rigo Branch: Changeset: r558:95c88bfbf9f7 Date: 2012-06-28 22:17 +0200 http://bitbucket.org/cffi/cffi/changeset/95c88bfbf9f7/ Log:Split this test in two. diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -1140,7 +1140,7 @@ p.a1 = ['x', 'y'] assert str(p.a1) == 'xyo' -def test_struct_return_in_func(): +def test_invalid_function_result_types(): BFunc = new_function_type((), new_void_type()) BArray = new_array_type(new_pointer_type(BFunc), 5)# works new_function_type((), BFunc)# works @@ -1150,6 +1150,7 @@ (), new_union_type("foo_u")) py.test.raises(TypeError, new_function_type, (), BArray) +def test_struct_return_in_func(): if sys.platform == 'win32': py.test.skip("function returning struct") BChar = new_primitive_type("char") ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Document function calls, including struct returns (next checkins).
Author: Armin Rigo Branch: Changeset: r561:29ca338c6740 Date: 2012-06-29 10:25 +0200 http://bitbucket.org/cffi/cffi/changeset/29ca338c6740/ Log:Document function calls, including struct returns (next checkins). diff --git a/doc/source/index.rst b/doc/source/index.rst --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -493,6 +493,50 @@ it all the time. +Function calls +-- + +When calling C functions, passing arguments follows mostly the same +rules as assigning to structure fields, and the return value follows the +same rules as reading a structure field. For example:: + +ffi.cdef(""" +int foo(int a, int b); +""") +lib = ffi.verify("#include ") + +n = lib.foo(2, 3) # returns a normal integer + +As an extension, you can pass to ``char *`` arguments a normal Python +string (but don't pass a normal Python string to functions that take a +``char *`` argument and may mutate it!):: + +ffi.cdef(""" +size_t strlen(const char *); +""") +C = ffi.dlopen(None) + +assert C.strlen("hello") == 5 + +CFFI supports passing and returning structs to functions and callbacks. +Example (sketch):: + +>>> ffi.cdef(""" +... struct foo_s { int a, b; }; +... struct foo_s function_returning_a_struct(void); +... """) +>>> lib = ffi.verify("#include ") +>>> lib.function_returning_a_struct() + + +There are a few "obscure-case" limitations to the argument types and +return type. You cannot pass directly as argument a union, nor a struct +which uses bitfields (note that passing a *pointer* to anything is +fine). If you pass a struct, the struct type cannot have been declared +with "``...;``" and completed with ``verify()``; you need to declare it +completely in ``cdef()``. + + Variadic function calls --- ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Exception to the no-keepalive rule: add one keepalive for a case
Author: Armin Rigo Branch: Changeset: r560:6b874784716c Date: 2012-06-29 10:24 +0200 http://bitbucket.org/cffi/cffi/changeset/6b874784716c/ Log:Exception to the no-keepalive rule: add one keepalive for a case that is occasionally hard to work around. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -41,7 +41,8 @@ #define CT_PRIMITIVE_FITS_LONG 2048 #define CT_IS_OPAQUE 4096 #define CT_IS_ENUM 8192 -#define CT_CUSTOM_FIELD_POS 16384 +#define CT_IS_PTR_TO_OWNED 16384 +#define CT_CUSTOM_FIELD_POS 32768 #define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED |\ CT_PRIMITIVE_UNSIGNED | \ CT_PRIMITIVE_CHAR | \ @@ -126,6 +127,11 @@ } CDataObject_own_length; typedef struct { +CDataObject_own_base head; +PyObject *structobj; +} CDataObject_own_structptr; + +typedef struct { ffi_cif cif; /* the following information is used when doing the call: - a buffer of size 'exchange_size' is malloced @@ -1007,7 +1013,10 @@ if (cdb->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) cdb); -if (cdb->head.c_type->ct_flags & CT_FUNCTIONPTR) { +if (cdb->head.c_type->ct_flags & CT_IS_PTR_TO_OWNED) { +Py_DECREF(((CDataObject_own_structptr *)cdb)->structobj); +} +else if (cdb->head.c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = (ffi_closure *)cdb->head.c_data; PyObject *args = (PyObject *)(closure->user_data); @@ -1275,15 +1284,33 @@ } static PyObject * -cdata_subscript(CDataObject *cd, PyObject *key) +cdataowning_subscript(CDataObject *cd, PyObject *key) { char *c = _cdata_get_indexed_ptr(cd, key); -CTypeDescrObject *ctitem = cd->c_type->ct_itemdescr; /* use 'mp_subscript' instead of 'sq_item' because we don't want negative indexes to be corrected automatically */ if (c == NULL) return NULL; -return convert_to_object(c, ctitem); + +if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { +PyObject *res = ((CDataObject_own_structptr *)cd)->structobj; +Py_INCREF(res); +return res; +} +else { +return convert_to_object(c, cd->c_type->ct_itemdescr); +} +} + +static PyObject * +cdata_subscript(CDataObject *cd, PyObject *key) +{ +char *c = _cdata_get_indexed_ptr(cd, key); +/* use 'mp_subscript' instead of 'sq_item' because we don't want + negative indexes to be corrected automatically */ +if (c == NULL) +return NULL; +return convert_to_object(c, cd->c_type->ct_itemdescr); } static int @@ -1603,6 +1630,12 @@ (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ }; +static PyMappingMethods CDataOwn_as_mapping = { +(lenfunc)cdata_length, /*mp_length*/ +(binaryfunc)cdataowning_subscript, /*mp_subscript*/ +(objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ +}; + static PyTypeObject CData_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.CData", @@ -1645,7 +1678,7 @@ (reprfunc)cdataowning_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ -0, /* tp_as_mapping */ +&CDataOwn_as_mapping, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ @@ -1752,6 +1785,7 @@ static PyObject *b_newp(PyObject *self, PyObject *args) { CTypeDescrObject *ct, *ctitem; +CDataObject *cd; CDataObject_own_base *cdb; PyObject *init = Py_None; Py_ssize_t dataoffset, datasize, explicitlength; @@ -1812,23 +1846,48 @@ cdb = (CDataObject_own_base *)PyObject_Malloc(dataoffset + datasize); if (PyObject_Init((PyObject *)cdb, &CDataOwning_Type) == NULL) return NULL; - -Py_INCREF(ct); -cdb->head.c_type = ct; +cdb->weakreflist = NULL; cdb->head.c_data = ((char *)cdb) + dataoffset; -cdb->weakreflist = NULL; if (explicitlength >= 0) ((CDataObject_own_length*)cdb)->length = explicitlength; -memset(cdb->head.c_data, 0, datasize); -if (init != Py_None) { -if (convert_from_object(cdb->head.c_data, - (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) { +if (ct->ct_flags & CT_IS_PTR_TO_OWNED) { +/* common case of ptr-to-struct (or ptr-to-union): for this case + we build two objects instead of one, with the memory-owning + one being really the struct (or union) and the returned one + having a strong reference to it */ +CDataObject_own_structptr *cdp; + +ctitem = ct->ct_itemdescr; +Py_INCREF(ctitem);
[pypy-commit] cffi default: hg backout 0ed9b03dd40d, f0cdef5768b5, 95c88bfbf9f7.
Author: Armin Rigo Branch: Changeset: r559:ae0b6ba4b07b Date: 2012-06-29 09:10 +0200 http://bitbucket.org/cffi/cffi/changeset/ae0b6ba4b07b/ Log:hg backout 0ed9b03dd40d, f0cdef5768b5, 95c88bfbf9f7. Will redo struct-returning functions slightly differently. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -22,11 +22,6 @@ # define USE__THREAD #endif -/* Define CAN_RETURN_STRUCTS if the C compiler supports returning structs */ -#if !defined(MS_WIN32) -# define CAN_RETURN_STRUCTS -#endif - // /* base type flag: exactly one of the following: */ @@ -1425,9 +1420,6 @@ return PyObject_GenericSetAttr((PyObject *)cd, attr, value); } -static PyObject * -convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/ - static cif_description_t * fb_prepare_cif(PyObject *fargs, CTypeDescrObject *fresult);/* forward */ @@ -1550,9 +1542,6 @@ res = Py_None; Py_INCREF(res); } -else if (fresult->ct_flags & CT_STRUCT) { -res = convert_struct_to_owning_object(resultdata, fresult); -} else { res = convert_to_object(resultdata, fresult); } @@ -1760,46 +1749,10 @@ // -static CDataObject *allocate_owning_object(Py_ssize_t dataoffset, - Py_ssize_t datasize, - CTypeDescrObject *ct) -{ -CDataObject_own_base *cdb; -cdb = (CDataObject_own_base *)PyObject_Malloc(dataoffset + datasize); -if (PyObject_Init((PyObject *)cdb, &CDataOwning_Type) == NULL) -return NULL; - -Py_INCREF(ct); -cdb->head.c_type = ct; -cdb->head.c_data = ((char *)cdb) + dataoffset; -cdb->weakreflist = NULL; -return &cdb->head; -} - -static PyObject * -convert_struct_to_owning_object(char *data, CTypeDescrObject *ct) -{ -CDataObject *cd; -Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment); -Py_ssize_t datasize = ct->ct_size; - -if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) != CT_STRUCT) { -PyErr_SetString(PyExc_TypeError, -"return type is not a struct or is opaque"); -return NULL; -} -cd = allocate_owning_object(dataoffset, datasize, ct); -if (cd == NULL) -return NULL; - -memcpy(cd->c_data, data, datasize); -return (PyObject *)cd; -} - static PyObject *b_newp(PyObject *self, PyObject *args) { CTypeDescrObject *ct, *ctitem; -CDataObject *cd; +CDataObject_own_base *cdb; PyObject *init = Py_None; Py_ssize_t dataoffset, datasize, explicitlength; if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init)) @@ -1856,21 +1809,26 @@ return NULL; } -cd = allocate_owning_object(dataoffset, datasize, ct); -if (cd == NULL) +cdb = (CDataObject_own_base *)PyObject_Malloc(dataoffset + datasize); +if (PyObject_Init((PyObject *)cdb, &CDataOwning_Type) == NULL) return NULL; + +Py_INCREF(ct); +cdb->head.c_type = ct; +cdb->head.c_data = ((char *)cdb) + dataoffset; +cdb->weakreflist = NULL; if (explicitlength >= 0) -((CDataObject_own_length*)cd)->length = explicitlength; - -memset(cd->c_data, 0, datasize); +((CDataObject_own_length*)cdb)->length = explicitlength; + +memset(cdb->head.c_data, 0, datasize); if (init != Py_None) { -if (convert_from_object(cd->c_data, +if (convert_from_object(cdb->head.c_data, (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) { -Py_DECREF(cd); +Py_DECREF(cdb); return NULL; } } -return (PyObject *)cd; +return (PyObject *)cdb; } static CDataObject *_new_casted_primitive(CTypeDescrObject *ct) @@ -2785,14 +2743,11 @@ if (PyErr_Occurred()) return -1; if (cif_descr != NULL) { -#ifndef CAN_RETURN_STRUCTS if (fb->rtype->type == FFI_TYPE_STRUCT) { PyErr_SetString(PyExc_NotImplementedError, -"functions returning structs are not supported " -"on this platform"); +"functions returning structs are not supported"); return -1; } -#endif /* exchange data size */ /* first, enough room for an array of 'nargs' pointers */ exchange_offset = nargs * sizeof(void*); @@ -2990,9 +2945,9 @@ &ellipsis)) return NULL; -if (fresult->ct_flags & CT_UNION) { +if (fresult->ct_flags & (CT_STRUCT|CT_UNION)) { PyErr_SetString(PyExc_NotImplementedError, -"functions returning a union"); +"functions returning a struct or a union"); return NULL; } if ((fresult->ct_si
[pypy-commit] cffi default: Add a passing test about callbacks returning structs.
Author: Armin Rigo Branch: Changeset: r563:c3e818533793 Date: 2012-06-29 10:49 +0200 http://bitbucket.org/cffi/cffi/changeset/c3e818533793/ Log:Add a passing test about callbacks returning structs. diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -878,6 +878,24 @@ for i, f in enumerate(flist): assert f(-142) == -142 + i +def test_callback_returning_struct(): +BSChar = new_primitive_type("signed char") +BInt = new_primitive_type("int") +BDouble = new_primitive_type("double") +BStruct = new_struct_type("foo") +BStructPtr = new_pointer_type(BStruct) +complete_struct_or_union(BStruct, [('a', BSChar, -1), + ('b', BDouble, -1)]) +def cb(n): +return newp(BStructPtr, [-n, 1E-42])[0] +BFunc = new_function_type((BInt,), BStruct) +f = callback(BFunc, cb) +s = f(10) +assert typeof(s) is BStruct +assert repr(s).startswith("http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Do again struct-returning funcs
Author: Armin Rigo Branch: Changeset: r562:d1ae2e54055d Date: 2012-06-29 10:42 +0200 http://bitbucket.org/cffi/cffi/changeset/d1ae2e54055d/ Log:Do again struct-returning funcs diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -1447,6 +1447,9 @@ return PyObject_GenericSetAttr((PyObject *)cd, attr, value); } +static PyObject * +convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/ + static cif_description_t * fb_prepare_cif(PyObject *fargs, CTypeDescrObject *fresult);/* forward */ @@ -1569,6 +1572,9 @@ res = Py_None; Py_INCREF(res); } +else if (fresult->ct_flags & CT_STRUCT) { +res = convert_struct_to_owning_object(resultdata, fresult); +} else { res = convert_to_object(resultdata, fresult); } @@ -1782,6 +1788,41 @@ // +static CDataObject_own_base *allocate_owning_object(Py_ssize_t size, +CTypeDescrObject *ct) +{ +CDataObject_own_base *cdb; +cdb = (CDataObject_own_base *)PyObject_Malloc(size); +if (PyObject_Init((PyObject *)cdb, &CDataOwning_Type) == NULL) +return NULL; + +Py_INCREF(ct); +cdb->head.c_type = ct; +cdb->weakreflist = NULL; +return cdb; +} + +static PyObject * +convert_struct_to_owning_object(char *data, CTypeDescrObject *ct) +{ +CDataObject_own_base *cdb; +Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment); +Py_ssize_t datasize = ct->ct_size; + +if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) != CT_STRUCT) { +PyErr_SetString(PyExc_TypeError, +"return type is not a struct or is opaque"); +return NULL; +} +cdb = allocate_owning_object(dataoffset + datasize, ct); +if (cdb == NULL) +return NULL; +cdb->head.c_data = ((char *)cdb) + dataoffset; + +memcpy(cdb->head.c_data, data, datasize); +return (PyObject *)cdb; +} + static PyObject *b_newp(PyObject *self, PyObject *args) { CTypeDescrObject *ct, *ctitem; @@ -1843,41 +1884,39 @@ return NULL; } -cdb = (CDataObject_own_base *)PyObject_Malloc(dataoffset + datasize); -if (PyObject_Init((PyObject *)cdb, &CDataOwning_Type) == NULL) -return NULL; -cdb->weakreflist = NULL; -cdb->head.c_data = ((char *)cdb) + dataoffset; -if (explicitlength >= 0) -((CDataObject_own_length*)cdb)->length = explicitlength; - if (ct->ct_flags & CT_IS_PTR_TO_OWNED) { /* common case of ptr-to-struct (or ptr-to-union): for this case we build two objects instead of one, with the memory-owning one being really the struct (or union) and the returned one having a strong reference to it */ -CDataObject_own_structptr *cdp; - -ctitem = ct->ct_itemdescr; -Py_INCREF(ctitem); -cdb->head.c_type = ctitem; - -cdp = (CDataObject_own_structptr *) -PyObject_Malloc(sizeof(CDataObject_own_structptr)); -if (PyObject_Init((PyObject *)cdp, &CDataOwning_Type) == NULL) { +CDataObject_own_base *cdp; + +cdb = allocate_owning_object(dataoffset + datasize, ct->ct_itemdescr); +if (cdb == NULL) +return NULL; + +cdp = allocate_owning_object(sizeof(CDataObject_own_structptr), ct); +if (cdp == NULL) { Py_DECREF(cdb); return NULL; } -cdp->head.weakreflist = NULL; -cdp->head.head.c_data = cdb->head.c_data; -cdp->structobj = (PyObject *)cdb; /* store away the only reference */ -cd = &cdp->head.head; +/* store the only reference to cdb into cdp */ +((CDataObject_own_structptr *)cdp)->structobj = (PyObject *)cdb; +assert(explicitlength < 0); + +cdb->head.c_data = cdp->head.c_data = ((char *)cdb) + dataoffset; +cd = &cdp->head; } else { +cdb = allocate_owning_object(dataoffset + datasize, ct); +if (cdb == NULL) +return NULL; + +cdb->head.c_data = ((char *)cdb) + dataoffset; +if (explicitlength >= 0) +((CDataObject_own_length*)cdb)->length = explicitlength; cd = &cdb->head; } -Py_INCREF(ct); -cd->c_type = ct; memset(cd->c_data, 0, datasize); if (init != Py_None) { @@ -2804,11 +2843,6 @@ if (PyErr_Occurred()) return -1; if (cif_descr != NULL) { -if (fb->rtype->type == FFI_TYPE_STRUCT) { -PyErr_SetString(PyExc_NotImplementedError, -"functions returning structs are not supported"); -return -1; -} /* exchange data size */ /* first, enough room for an array of 'nargs' pointers */ exchange_offset = nargs * sizeof(void*); @@ -3006,9 +3040,9 @@ &ellipsis))
[pypy-commit] cffi default: Test and implementation (again) for verify().
Author: Armin Rigo Branch: Changeset: r564:a506f1856eb6 Date: 2012-06-29 10:49 +0200 http://bitbucket.org/cffi/cffi/changeset/a506f1856eb6/ Log:Test and implementation (again) for verify(). diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -3694,6 +3694,7 @@ _cffi_from_c_char, convert_to_object, convert_from_object, +convert_struct_to_owning_object, }; // diff --git a/cffi/verifier.py b/cffi/verifier.py --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -184,6 +184,9 @@ elif isinstance(tp, model.ArrayType): return '_cffi_from_c_deref((char *)%s, _cffi_type(%d))' % ( var, self.gettypenum(tp)) +elif isinstance(tp, model.StructType): +return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( +var, self.gettypenum(tp)) else: raise NotImplementedError(tp) @@ -614,7 +617,9 @@ ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) #define _cffi_to_c \ ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) -#define _CFFI_NUM_EXPORTS 18 +#define _cffi_from_c_struct \ +((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) +#define _CFFI_NUM_EXPORTS 19 #if SIZEOF_LONG < SIZEOF_LONG_LONG # define _cffi_to_c_long_long PyLong_AsLongLong diff --git a/testing/test_verify.py b/testing/test_verify.py --- a/testing/test_verify.py +++ b/testing/test_verify.py @@ -576,3 +576,23 @@ """) msg = 'cannot pass as a argument a struct that was completed with verify()' assert msg in str(e.value) + +def test_func_returns_struct(): +ffi = FFI() +ffi.cdef(""" +struct foo_s { int aa, bb; }; +struct foo_s foo(int a, int b); +""") +lib = ffi.verify(""" +struct foo_s { int aa, bb; }; +struct foo_s foo(int a, int b) { +struct foo_s r; +r.aa = a*a; +r.bb = b*b; +return r; +} +""") +s = lib.foo(6, 7) +assert repr(s) == "" +assert s.aa == 36 +assert s.bb == 49 ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Document "new in version 0.2".
Author: Armin Rigo Branch: Changeset: r565:d3ad38171573 Date: 2012-06-29 10:52 +0200 http://bitbucket.org/cffi/cffi/changeset/d3ad38171573/ Log:Document "new in version 0.2". diff --git a/doc/source/index.rst b/doc/source/index.rst --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -536,6 +536,9 @@ with "``...;``" and completed with ``verify()``; you need to declare it completely in ``cdef()``. +.. versionadded:: 0.2 + Aside from these limitations, functions and callbacks can return structs. + Variadic function calls --- ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Add more tests for struct returns.
Author: Armin Rigo Branch: Changeset: r566:c2e7a851edcb Date: 2012-06-29 10:58 +0200 http://bitbucket.org/cffi/cffi/changeset/c2e7a851edcb/ Log:Add more tests for struct returns. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -3523,6 +3523,33 @@ return result; } +struct _testfunc11_s { int a1, a2; }; +static struct _testfunc11_s _testfunc11(int n) +{ +struct _testfunc11_s result; +result.a1 = n; +result.a2 = n * n; +return result; +} + +struct _testfunc12_s { double a1; }; +static struct _testfunc12_s _testfunc12(int n) +{ +struct _testfunc12_s result; +result.a1 = n; +return result; +} + +struct _testfunc13_s { int a1, a2, a3; }; +static struct _testfunc13_s _testfunc13(int n) +{ +struct _testfunc13_s result; +result.a1 = n; +result.a2 = n * n; +result.a3 = n * n * n; +return result; +} + static PyObject *b__testfunc(PyObject *self, PyObject *args) { /* for testing only */ @@ -3542,6 +3569,9 @@ case 8: f = stderr; break; case 9: f = &_testfunc9; break; case 10: f = &_testfunc10; break; +case 11: f = &_testfunc11; break; +case 12: f = &_testfunc12; break; +case 13: f = &_testfunc13; break; default: PyErr_SetNone(PyExc_ValueError); return NULL; diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -1171,6 +1171,7 @@ def test_struct_return_in_func(): BChar = new_primitive_type("char") BShort = new_primitive_type("short") +BDouble = new_primitive_type("double") BInt = new_primitive_type("int") BStruct = new_struct_type("foo_s") complete_struct_or_union(BStruct, [('a1', BChar, -1), @@ -1181,6 +1182,37 @@ assert repr(s) == "" assert s.a1 == chr(40) assert s.a2 == 40 * 40 +# +BStruct11 = new_struct_type("test11") +complete_struct_or_union(BStruct11, [('a1', BInt, -1), + ('a2', BInt, -1)]) +BFunc11 = new_function_type((BInt,), BStruct11) +f = cast(BFunc11, _testfunc(11)) +s = f(40) +assert repr(s) == "" +assert s.a1 == 40 +assert s.a2 == 40 * 40 +# +BStruct12 = new_struct_type("test12") +complete_struct_or_union(BStruct12, [('a1', BDouble, -1), + ]) +BFunc12 = new_function_type((BInt,), BStruct12) +f = cast(BFunc12, _testfunc(12)) +s = f(40) +assert repr(s) == "" +assert s.a1 == 40.0 +# +BStruct13 = new_struct_type("test13") +complete_struct_or_union(BStruct13, [('a1', BInt, -1), + ('a2', BInt, -1), + ('a3', BInt, -1)]) +BFunc13 = new_function_type((BInt,), BStruct13) +f = cast(BFunc13, _testfunc(13)) +s = f(40) +assert repr(s) == "" +assert s.a1 == 40 +assert s.a2 == 40 * 40 +assert s.a3 == 40 * 40 * 40 def test_cast_with_functionptr(): BFunc = new_function_type((), new_void_type()) ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: More tests for MSVC's struct return type. Add a workaround similar
Author: Armin Rigo Branch: Changeset: r567:ee603675e7aa Date: 2012-06-29 11:26 +0200 http://bitbucket.org/cffi/cffi/changeset/ee603675e7aa/ Log:More tests for MSVC's struct return type. Add a workaround similar to the one present in ctypes. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -2747,7 +2747,8 @@ } } -static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct) +static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, + int is_result_type) { if (ct->ct_flags & CT_PRIMITIVE_ANY) { return (ffi_type *)ct->ct_extra; @@ -2785,6 +2786,19 @@ return NULL; } +#ifdef USE_C_LIBFFI_MSVC +/* MSVC returns small structures in registers. Pretend int32 or + int64 return type. This is needed as a workaround for what + is really a bug of libffi_msvc seen as an independent library + (ctypes has a similar workaround). */ +if (is_result_type) { +if (ct->ct_size <= 4) +return &ffi_type_sint32; +if (ct->ct_size <= 8) +return &ffi_type_sint64; +} +#endif + n = PyDict_Size(ct->ct_stuff); elements = fb_alloc(fb, (n + 1) * sizeof(ffi_type*)); cf = (CFieldObject *)ct->ct_extra; @@ -2796,7 +2810,7 @@ "cannot pass as argument a struct with bit fields"); return NULL; } -ffifield = fb_fill_type(fb, cf->cf_type); +ffifield = fb_fill_type(fb, cf->cf_type, 0); if (elements != NULL) elements[i] = ffifield; cf = cf->cf_next; @@ -2839,7 +2853,7 @@ fb->nargs = nargs; /* ffi buffer: next comes the result type */ -fb->rtype = fb_fill_type(fb, fresult); +fb->rtype = fb_fill_type(fb, fresult, 1); if (PyErr_Occurred()) return -1; if (cif_descr != NULL) { @@ -2867,7 +2881,7 @@ /* ffi buffer: fill in the ffi for the i'th argument */ assert(farg != NULL); -atype = fb_fill_type(fb, farg); +atype = fb_fill_type(fb, farg, 0); if (PyErr_Occurred()) return -1; @@ -3550,6 +3564,41 @@ return result; } +struct _testfunc14_s { float a1; }; +static struct _testfunc14_s _testfunc14(int n) +{ +struct _testfunc14_s result; +result.a1 = (float)n; +return result; +} + +struct _testfunc15_s { float a1; int a2; }; +static struct _testfunc15_s _testfunc15(int n) +{ +struct _testfunc15_s result; +result.a1 = (float)n; +result.a2 = n * n; +return result; +} + +struct _testfunc16_s { float a1, a2; }; +static struct _testfunc16_s _testfunc16(int n) +{ +struct _testfunc16_s result; +result.a1 = (float)n; +result.a2 = -(float)n; +return result; +} + +struct _testfunc17_s { int a1; float a2; }; +static struct _testfunc17_s _testfunc17(int n) +{ +struct _testfunc17_s result; +result.a1 = n; +result.a2 = (float)n * (float)n; +return result; +} + static PyObject *b__testfunc(PyObject *self, PyObject *args) { /* for testing only */ @@ -3572,6 +3621,10 @@ case 11: f = &_testfunc11; break; case 12: f = &_testfunc12; break; case 13: f = &_testfunc13; break; +case 14: f = &_testfunc14; break; +case 15: f = &_testfunc15; break; +case 16: f = &_testfunc16; break; +case 17: f = &_testfunc17; break; default: PyErr_SetNone(PyExc_ValueError); return NULL; diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -1171,6 +1171,7 @@ def test_struct_return_in_func(): BChar = new_primitive_type("char") BShort = new_primitive_type("short") +BFloat = new_primitive_type("float") BDouble = new_primitive_type("double") BInt = new_primitive_type("int") BStruct = new_struct_type("foo_s") @@ -1213,6 +1214,45 @@ assert s.a1 == 40 assert s.a2 == 40 * 40 assert s.a3 == 40 * 40 * 40 +# +BStruct14 = new_struct_type("test14") +complete_struct_or_union(BStruct14, [('a1', BFloat, -1), + ]) +BFunc14 = new_function_type((BInt,), BStruct14) +f = cast(BFunc14, _testfunc(14)) +s = f(40) +assert repr(s) == "" +assert s.a1 == 40.0 +# +BStruct15 = new_struct_type("test15") +complete_struct_or_union(BStruct15, [('a1', BFloat, -1), + ('a2', BInt, -1)]) +BFunc15 = new_function_type((BInt,), BStruct15) +f = cast(BFunc15, _testfunc(15)) +s = f(40) +assert repr(s) == "" +assert s.a1 == 40.0 +assert s.a2 == 40 * 40 +# +BStruct16 = new_struct_type("test16") +complete_struct_or_union(BStruct16, [('a1', BFloat, -1), + ('a2', BFloat, -1)]) +BFunc16 = new_function_type((BInt,), BStruct16) +f = cas
[pypy-commit] pypy default: Merged in ltratt/pypy (pull request #73)
Author: Maciej Fijalkowski Branch: Changeset: r55872:26b81a6d9365 Date: 2012-06-29 12:26 +0200 http://bitbucket.org/pypy/pypy/changeset/26b81a6d9365/ Log:Merged in ltratt/pypy (pull request #73) diff --git a/pypy/module/select/interp_kqueue.py b/pypy/module/select/interp_kqueue.py --- a/pypy/module/select/interp_kqueue.py +++ b/pypy/module/select/interp_kqueue.py @@ -7,6 +7,7 @@ from pypy.rpython.lltypesystem import rffi, lltype from pypy.rpython.tool import rffi_platform from pypy.translator.tool.cbuild import ExternalCompilationInfo +import sys eci = ExternalCompilationInfo( @@ -20,14 +21,26 @@ _compilation_info_ = eci -CConfig.kevent = rffi_platform.Struct("struct kevent", [ -("ident", rffi.UINTPTR_T), -("filter", rffi.SHORT), -("flags", rffi.USHORT), -("fflags", rffi.UINT), -("data", rffi.INTPTR_T), -("udata", rffi.VOIDP), -]) +if "openbsd" in sys.platform: +IDENT_UINT = True +CConfig.kevent = rffi_platform.Struct("struct kevent", [ +("ident", rffi.UINT), +("filter", rffi.SHORT), +("flags", rffi.USHORT), +("fflags", rffi.UINT), +("data", rffi.INT), +("udata", rffi.VOIDP), +]) +else: +IDENT_UINT = False +CConfig.kevent = rffi_platform.Struct("struct kevent", [ +("ident", rffi.UINTPTR_T), +("filter", rffi.SHORT), +("flags", rffi.USHORT), +("fflags", rffi.UINT), +("data", rffi.INTPTR_T), +("udata", rffi.VOIDP), +]) CConfig.timespec = rffi_platform.Struct("struct timespec", [ @@ -243,16 +256,24 @@ self.event.c_udata = rffi.cast(rffi.VOIDP, udata) def _compare_all_fields(self, other, op): -l_ident = self.event.c_ident -r_ident = other.event.c_ident +if IDENT_UINT: +l_ident = rffi.cast(lltype.Unsigned, self.event.c_ident) +r_ident = rffi.cast(lltype.Unsigned, other.event.c_ident) +else: +l_ident = self.event.c_ident +r_ident = other.event.c_ident l_filter = rffi.cast(lltype.Signed, self.event.c_filter) r_filter = rffi.cast(lltype.Signed, other.event.c_filter) l_flags = rffi.cast(lltype.Unsigned, self.event.c_flags) r_flags = rffi.cast(lltype.Unsigned, other.event.c_flags) l_fflags = rffi.cast(lltype.Unsigned, self.event.c_fflags) r_fflags = rffi.cast(lltype.Unsigned, other.event.c_fflags) -l_data = self.event.c_data -r_data = other.event.c_data +if IDENT_UINT: +l_data = rffi.cast(lltype.Signed, self.event.c_data) +r_data = rffi.cast(lltype.Signed, other.event.c_data) +else: +l_data = self.event.c_data +r_data = other.event.c_data l_udata = rffi.cast(lltype.Unsigned, self.event.c_udata) r_udata = rffi.cast(lltype.Unsigned, other.event.c_udata) ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy default: Use appropriate types for struct kevent on OpenBSD.
Author: Laurence Tratt Branch: Changeset: r55871:6942c79aa982 Date: 2012-06-27 12:03 +0100 http://bitbucket.org/pypy/pypy/changeset/6942c79aa982/ Log:Use appropriate types for struct kevent on OpenBSD. Without this, RPython's type system spots something's wrong and throws an error; even if it didn't, the resulting C code would probably have been wrong. diff --git a/pypy/module/select/interp_kqueue.py b/pypy/module/select/interp_kqueue.py --- a/pypy/module/select/interp_kqueue.py +++ b/pypy/module/select/interp_kqueue.py @@ -7,6 +7,7 @@ from pypy.rpython.lltypesystem import rffi, lltype from pypy.rpython.tool import rffi_platform from pypy.translator.tool.cbuild import ExternalCompilationInfo +import sys eci = ExternalCompilationInfo( @@ -20,14 +21,26 @@ _compilation_info_ = eci -CConfig.kevent = rffi_platform.Struct("struct kevent", [ -("ident", rffi.UINTPTR_T), -("filter", rffi.SHORT), -("flags", rffi.USHORT), -("fflags", rffi.UINT), -("data", rffi.INTPTR_T), -("udata", rffi.VOIDP), -]) +if "openbsd" in sys.platform: +IDENT_UINT = True +CConfig.kevent = rffi_platform.Struct("struct kevent", [ +("ident", rffi.UINT), +("filter", rffi.SHORT), +("flags", rffi.USHORT), +("fflags", rffi.UINT), +("data", rffi.INT), +("udata", rffi.VOIDP), +]) +else: +IDENT_UINT = False +CConfig.kevent = rffi_platform.Struct("struct kevent", [ +("ident", rffi.UINTPTR_T), +("filter", rffi.SHORT), +("flags", rffi.USHORT), +("fflags", rffi.UINT), +("data", rffi.INTPTR_T), +("udata", rffi.VOIDP), +]) CConfig.timespec = rffi_platform.Struct("struct timespec", [ @@ -243,16 +256,24 @@ self.event.c_udata = rffi.cast(rffi.VOIDP, udata) def _compare_all_fields(self, other, op): -l_ident = self.event.c_ident -r_ident = other.event.c_ident +if IDENT_UINT: +l_ident = rffi.cast(lltype.Unsigned, self.event.c_ident) +r_ident = rffi.cast(lltype.Unsigned, other.event.c_ident) +else: +l_ident = self.event.c_ident +r_ident = other.event.c_ident l_filter = rffi.cast(lltype.Signed, self.event.c_filter) r_filter = rffi.cast(lltype.Signed, other.event.c_filter) l_flags = rffi.cast(lltype.Unsigned, self.event.c_flags) r_flags = rffi.cast(lltype.Unsigned, other.event.c_flags) l_fflags = rffi.cast(lltype.Unsigned, self.event.c_fflags) r_fflags = rffi.cast(lltype.Unsigned, other.event.c_fflags) -l_data = self.event.c_data -r_data = other.event.c_data +if IDENT_UINT: +l_data = rffi.cast(lltype.Signed, self.event.c_data) +r_data = rffi.cast(lltype.Signed, other.event.c_data) +else: +l_data = self.event.c_data +r_data = other.event.c_data l_udata = rffi.cast(lltype.Unsigned, self.event.c_udata) r_udata = rffi.cast(lltype.Unsigned, other.event.c_udata) ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: add license to MANIFEST.in
Author: Maciej Fijalkowski Branch: Changeset: r568:7d9ca9550bd3 Date: 2012-06-29 12:28 +0200 http://bitbucket.org/cffi/cffi/changeset/7d9ca9550bd3/ Log:add license to MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ recursive-include cffi *.py recursive-include c *.c *.h *.asm recursive-include testing *.py -recursive-include doc *.py *.rst Makefile *.bat +recursive-include doc *.py *.rst Makefile *.bat LICENSE ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Add a test that the version is consistent.
Author: Armin Rigo Branch: Changeset: r569:e96c7e18aecf Date: 2012-06-29 12:41 +0200 http://bitbucket.org/cffi/cffi/changeset/e96c7e18aecf/ Log:Add a test that the version is consistent. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -3815,5 +3815,9 @@ if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0) return; +v = PyString_FromString("0.2"); +if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0) +return; + init_errno(); } diff --git a/cffi/__init__.py b/cffi/__init__.py --- a/cffi/__init__.py +++ b/cffi/__init__.py @@ -3,3 +3,6 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing + +__version__ = "0.2" +__version_info__ = (0, 2) diff --git a/testing/test_version.py b/testing/test_version.py new file mode 100644 --- /dev/null +++ b/testing/test_version.py @@ -0,0 +1,16 @@ +import os +import cffi, _cffi_backend + +def test_version(): +v = cffi.__version__ +assert v == '%s.%s' % cffi.__version_info__ +assert v == _cffi_backend.__version__ + +def test_doc_version(): +parent = os.path.dirname(os.path.dirname(__file__)) +p = os.path.join(parent, 'doc', 'source', 'conf.py') +content = file(p).read() +# +v = cffi.__version__ +assert ("version = '%s'\n" % v) in content +assert ("release = '%s'\n" % v) in content ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Documentation updates
Author: Armin Rigo Branch: Changeset: r570:71f5e672a341 Date: 2012-06-29 16:52 +0200 http://bitbucket.org/cffi/cffi/changeset/71f5e672a341/ Log:Documentation updates diff --git a/doc/source/index.rst b/doc/source/index.rst --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -242,7 +242,7 @@ size_t, ssize_t As we will see on `the verification step`_ below, the declarations can -also contain "``...``" at various places; there are placeholders that will +also contain "``...``" at various places; these are placeholders that will be completed by a call to ``verify()``. @@ -250,11 +250,14 @@ - ``ffi.dlopen(libpath)``: this function opens a shared library and -returns a module-like library object. You can use the library object to -call the functions previously declared by ``ffi.cdef()``, and to read or -write global variables. Note that you can use a single ``cdef()`` to -declare functions from multiple libraries, as long as you load each of -them with ``dlopen()`` and access the functions from the correct one. +returns a module-like library object. You need to use *either* +``ffi.dlopen()`` *or* ``ffi.verify()``, documented below_. + +You can use the library object to call the functions previously declared +by ``ffi.cdef()``, and to read or write global variables. Note that you +can use a single ``cdef()`` to declare functions from multiple +libraries, as long as you load each of them with ``dlopen()`` and access +the functions from the correct one. The ``libpath`` is the file name of the shared library, which can contain a full path or not (in which case it is searched in standard @@ -274,6 +277,8 @@ cannot call functions from a library without linking it in your program, as ``dlopen()`` does dynamically in C. +.. _below: + The verification step - @@ -281,12 +286,15 @@ ``ffi.verify(source, **kwargs)``: verifies that the current ffi signatures compile on this machine, and return a dynamic library object. The dynamic library can be used to call functions and access global -variables declared by a previous ``ffi.cdef()``. The library is compiled -by the C compiler: it gives you C-level API compatibility (including -calling macros, as long as you declared them as functions in -``ffi.cdef()``). This differs from ``ffi.dlopen()``, which requires -ABI-level compatibility and must be called several times to open several -shared libraries. +variables declared by a previous ``ffi.cdef()``. You don't need to use +``ffi.dlopen()`` in this case. + +The returned library is a custom one, compiled just-in-time by the C +compiler: it gives you C-level API compatibility (including calling +macros, as long as you declared them as functions in ``ffi.cdef()``). +This differs from ``ffi.dlopen()``, which requires ABI-level +compatibility and must be called several times to open several shared +libraries. On top of CPython, the new library is actually a CPython C extension module. This solution constrains you to have a C compiler (future work @@ -322,16 +330,19 @@ if you pass a ``int *`` argument to a function expecting a ``long *``. Moreover, you can use "``...``" in the following places in the ``cdef()`` -for leaving details unspecified (filled in by the C compiler): +for leaving details unspecified, which are then completed by the C +compiler during ``verify()``: * structure declarations: any ``struct`` that ends with "``...;``" is - partial. It will be completed by the compiler. (But note that you - can only access fields that you declared.) Any ``struct`` - declaration without "``...;``" is assumed to be exact, and this is + partial: it may be missing fields and/or have them declared out of order. + This declaration will be corrected by the compiler. (But note that you + can only access fields that you declared, not others.) Any ``struct`` + declaration which doesn't use "``...``" is assumed to be exact, but this is checked: you get a ``VerificationError`` if it is not. * unknown types: the syntax "``typedef ... foo_t;``" declares the type - ``foo_t`` as opaque. + ``foo_t`` as opaque. Useful mainly for when the API takes and returns + ``foo_t *`` without you needing to looking inside the ``foo_t``. * array lengths: when used as structure fields, arrays can have an unspecified length, as in "``int n[];``". The length is completed @@ -356,6 +367,14 @@ to write the ``const`` together with the variable name, as in ``static char *const FOO;``). +Currently, finding automatically the size of an integer type is not +supported. You need to declare them with ``typedef int myint;`` or +``typedef long myint;`` or ``typedef long long myint;`` or their +unsigned equivalent. Depending on the usage, the C compiler might give +warnings if you misdeclare ``myint`` as the wrong type even if it is +equivalent on this platform (e.g. using ``long`` instead of ``long +long`` or vice-versa on 64-
[pypy-commit] cffi default: Add MacOS 10.6 instructions.
Author: Armin Rigo Branch: Changeset: r571:f081fe201bd4 Date: 2012-06-29 17:17 +0200 http://bitbucket.org/cffi/cffi/changeset/f081fe201bd4/ Log:Add MacOS 10.6 instructions. diff --git a/doc/source/index.rst b/doc/source/index.rst --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -71,6 +71,8 @@ * https://bitbucket.org/cffi/cffi/downloads * ``python setup.py install`` or ``python setup_base.py install`` + (should work out of the box on Ubuntu or Windows; see below for + `MacOS 10.6`_) * or you can directly import and use ``cffi``, but if you don't compile the ``_cffi_backend`` extension module, it will fall back @@ -91,6 +93,41 @@ .. _`testing/test_verify.py`: https://bitbucket.org/cffi/cffi/src/default/testing/test_verify.py +Platform-specific instructions +-- + +``libffi`` is notoriously messy to install and use --- to the point that +CPython includes its own copy to avoid relying on external packages. +CFFI did the same for Windows, but (so far) not for other platforms. +Ubuntu Linux seems to work out of the box. Here are some +(user-supplied) instructions for other platforms. + + +MacOS 10.6 +++ + +(Thanks Juraj Sukop for this) + +For building libffi you can use the default install path, but then, in +``setup.py`` you need to change:: + +include_dirs = [] + +to:: + +include_dirs = ['/usr/local/lib/libffi-3.0.11/include'] + +Then running ``python setup.py build`` complains about "fatal error: error writing to -: Broken pipe", which can be fixed by running:: + +ARCHFLAGS="-arch i386 -arch x86_64" python setup.py build + +as described here_. + +.. _here: http://superuser.com/questions/259278/python-2-6-1-pycrypto-2-3-pypi-package-broken-pipe-during-build + + +=== + Examples === ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Give again the link to the demo directory here.
Author: Armin Rigo Branch: Changeset: r572:70101d453a7f Date: 2012-06-29 18:09 +0200 http://bitbucket.org/cffi/cffi/changeset/70101d453a7f/ Log:Give again the link to the demo directory here. diff --git a/doc/source/index.rst b/doc/source/index.rst --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -173,6 +173,9 @@ ``struct passwd``, but so far require a C compiler at runtime. (We plan to improve with caching and a way to distribute the compiled code.) +You will find a number of larger examples using ``verify()`` in the +`demo`_ directory. + Struct/Array Example ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] extradoc extradoc: Add a note
Author: Armin Rigo Branch: extradoc Changeset: r4221:45b651669f9c Date: 2012-06-29 19:43 +0200 http://bitbucket.org/pypy/extradoc/changeset/45b651669f9c/ Log:Add a note diff --git a/talk/ep2012/stm/talk.rst b/talk/ep2012/stm/talk.rst --- a/talk/ep2012/stm/talk.rst +++ b/talk/ep2012/stm/talk.rst @@ -56,6 +56,8 @@ moved from 'alpha' to 'beta': it runs e.g. a big part of **PyOpenSSL** and **lxml** +* py3k in progress (but 2.7 support never going away) + PyPy organization - ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] extradoc extradoc: Add a draft of the first part
Author: Armin Rigo Branch: extradoc Changeset: r4222:cba08044f438 Date: 2012-06-29 19:44 +0200 http://bitbucket.org/pypy/extradoc/changeset/cba08044f438/ Log:Add a draft of the first part diff --git a/talk/ep2012/stm/stm.txt b/talk/ep2012/stm/stm.txt new file mode 100644 --- /dev/null +++ b/talk/ep2012/stm/stm.txt @@ -0,0 +1,113 @@ + + +Problem +--- + + Python is slow-ish, by some factor N + + (Python / other lang) ~= N ~= const + + CPU speed used to grow exponentially, but no longer + + one program written in Python runs on one core only + + which means that one program written in Python will in the future run + exponentially slower, when compared with "other lang" + + does not matter for all programs... or does it? think about it this way: + +1. my script runs anyway in 0.1 seconds. + + Yes, but what if you were running it on 2002 hardware? it would take + 3 seconds. On 1982 hardware? One hour. So if the CPU speed growth + stop had occurred in 1982 already, then your script would still take + one hour today to run in Python. (Or half an hour thanks to the + continuing hard work of a dedicated core team...) + +2. I can use other solutions involving launching multiple processes + and exchanging data between them. + + Yes, which is fine. For some problems it is the "correct" + solution (separation for security, etc.). But for some other + problems it doesn't apply or at least not easily. Imagine a + Python without GC. You can of course handle manually allocating + and freeing objects, like in C++. But you're missing a vast + simplification that you get for free in Python. + + +This presentation is not about removing the GIL +--- + +pypy-stm is a Python without the GIL, the fourth in this category: + + - Python 1.4 patch by Greg Stein in 1996 + - Jython + - IronPython + +Demo pypy-stm + +No JIT integration so far, about 4x slower than a JIT-less PyPy + +Will talk later about "STM". + +Some hardware support (HTM) coming in 2013 (Intel's Haswell CPU), +which promizes to make it easy to do the same with CPython + +So removing the GIL is suddenly around the corner + + +The catch +- + +You have to use threads + + +Threads +--- + +Threads are messy to use correctly + +Similar to doing explicit memory management: I would like my program to +figure it automatically, not have to worry about it every single line of +code. + +Debugging a race condition is a nightmare, totally non-reproductible. + + +This presentation is really about this new feature +-- + +Demo: pypy-stm using the "transaction" module + +Demo how to insert usage of it in pypy/rpython/rtyper.py + + +What you get + + +A fool-proof API that gives multicore usages *without using threads* + +Implemented in pypy-stm --- slowly, but who cares? :-) when you have +an unlimited supply of cores... (ok, I agree we care anyway.) + +How? See below. + + +What about CPython? +--- + +HTM coming in Intel's Haswell CPU is not going to be enough at all for +this. It'll eventually get there, but in how many years? and how many +more years before we can assume that every CPU out there has it? + +In the meantime there seem to be no move from the CPython core +developers to try to implement STM. It would be a major undertaking. + +So the future looks to me like: (CPython / other lang) will go down +exponentially until the point, in 10-20 years, where HTM is good +enough for CPython. A "dark age" of CPython... + + +Transactional Memory + + ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy kill-import_from_lib_pypy: move config cache recreation code to pypy/tool/lib_pypy
Author: Ronny Pfannschmidt Branch: kill-import_from_lib_pypy Changeset: r55873:95707b7b2e26 Date: 2012-06-29 21:26 +0200 http://bitbucket.org/pypy/pypy/changeset/95707b7b2e26/ Log:move config cache recreation code to pypy/tool/lib_pypy diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py b/lib_pypy/ctypes_config_cache/dumpcache.py deleted file mode 100644 --- a/lib_pypy/ctypes_config_cache/dumpcache.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -from ctypes_configure import dumpcache -from pypy.jit.backend import detect_cpu - -def dumpcache2(basename, config): -model = detect_cpu.autodetect_main_model_and_size() -filename = '_%s_%s_.py' % (basename, model) -dumpcache.dumpcache(__file__, filename, config) -# -filename = os.path.join(os.path.dirname(__file__), -'_%s_cache.py' % (basename,)) -g = open(filename, 'w') -print >> g, '''\ -try: -from __pypy__ import cpumodel -except ImportError: -from pypy.jit.backend import detect_cpu -cpumodel = detect_cpu.autodetect_main_model_and_size() -# XXX relative import, should be removed together with -# XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib -mod = __import__("_%s_%%s_" %% (cpumodel,), - globals(), locals(), ["*"]) -globals().update(mod.__dict__)\ -''' % (basename,) -g.close() diff --git a/lib_pypy/ctypes_config_cache/rebuild.py b/lib_pypy/ctypes_config_cache/rebuild.py --- a/lib_pypy/ctypes_config_cache/rebuild.py +++ b/lib_pypy/ctypes_config_cache/rebuild.py @@ -10,55 +10,7 @@ autopath_py = os.path.abspath(autopath_py) execfile(autopath_py, dict(__name__='autopath', __file__=autopath_py)) -import os, sys -import py - -_dirpath = os.path.dirname(__file__) or os.curdir - -from pypy.tool.ansi_print import ansi_log -log = py.log.Producer("ctypes_config_cache") -py.log.setconsumer("ctypes_config_cache", ansi_log) - - -def rebuild_one(name): -filename = os.path.join(_dirpath, name) -d = {'__file__': filename} -path = sys.path[:] -try: -sys.path.insert(0, _dirpath) -execfile(filename, d) -finally: -sys.path[:] = path - -def try_rebuild(): -from pypy.jit.backend import detect_cpu -model = detect_cpu.autodetect_main_model_and_size() -# remove the files '_*_model_.py' -left = {} -for p in os.listdir(_dirpath): -if p.startswith('_') and (p.endswith('_%s_.py' % model) or - p.endswith('_%s_.pyc' % model)): -os.unlink(os.path.join(_dirpath, p)) -elif p.startswith('_') and (p.endswith('_.py') or -p.endswith('_.pyc')): -for i in range(2, len(p)-4): -left[p[:i]] = True -# remove the files '_*_cache.py' if there is no '_*_*_.py' left around -for p in os.listdir(_dirpath): -if p.startswith('_') and (p.endswith('_cache.py') or - p.endswith('_cache.pyc')): -if p[:-9] not in left: -os.unlink(os.path.join(_dirpath, p)) -# -for p in os.listdir(_dirpath): -if p.endswith('.ctc.py'): -try: -rebuild_one(p) -except Exception, e: -log.ERROR("Running %s:\n %s: %s" % ( -os.path.join(_dirpath, p), -e.__class__.__name__, e)) - +from pypy.tool.lib_pypy import try_rebuild if __name__ == '__main__': try_rebuild() diff --git a/pypy/tool/lib_pypy.py b/pypy/tool/lib_pypy.py --- a/pypy/tool/lib_pypy.py +++ b/pypy/tool/lib_pypy.py @@ -1,8 +1,91 @@ +import os +import sys + import py import pypy import pypy.module from pypy.module.sys.version import CPYTHON_VERSION +from ctypes_configure import dumpcache +from pypy.jit.backend import detect_cpu + + +from pypy.tool.ansi_print import ansi_log +log = py.log.Producer("ctypes_config_cache") +py.log.setconsumer("ctypes_config_cache", ansi_log) + + LIB_ROOT = py.path.local(pypy.__path__[0]).dirpath() LIB_PYPY = LIB_ROOT.join('lib_pypy') LIB_PYTHON = LIB_ROOT.join('lib-python', '%d.%d' % CPYTHON_VERSION[:2]) + + +ctypes_cachedir = LIB_PYPY.join('ctypes_config_cache') + + +def dumpcache2(basename, config, sourcefile): +model = detect_cpu.autodetect_main_model_and_size() +filename = '_%s_%s_.py' % (basename, model) +dumpcache.dumpcache(sourcefile, filename, config) +# +filename = ctypes_cachedir.join('_%s_cache.py' % (basename)) +filename.write('''\ +try: +from __pypy__ import cpumodel +except ImportError: +from pypy.jit.backend import detect_cpu +cpumodel = detect_cpu.autodetect_main_model_and_size() +# XXX relative import, should be removed together with +# XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib +mod = __import__("_BASENAME_%s_" % (cpumodel,), + globals(), locals(), ["*"]) +globals().update(mod.__dict__)\\ +'''.replace("BASENAME", basename)) + + + + + +def rebuild_on
[pypy-commit] pypy kill-import_from_lib_pypy: move the dump writing from the ctypes config cache to tool.lib_pypy
Author: Ronny Pfannschmidt Branch: kill-import_from_lib_pypy Changeset: r55874:87755db8d523 Date: 2012-06-29 21:34 +0200 http://bitbucket.org/pypy/pypy/changeset/87755db8d523/ Log:move the dump writing from the ctypes config cache to tool.lib_pypy diff --git a/lib_pypy/ctypes_config_cache/locale.ctc.py b/lib_pypy/ctypes_config_cache/locale.ctc.py --- a/lib_pypy/ctypes_config_cache/locale.ctc.py +++ b/lib_pypy/ctypes_config_cache/locale.ctc.py @@ -5,7 +5,6 @@ from ctypes_configure.configure import (configure, ExternalCompilationInfo, ConstantInteger, DefinedConstantInteger, SimpleType, check_eci) -import dumpcache # @@ -70,4 +69,3 @@ config['ALL_CONSTANTS'] = tuple(_CONSTANTS) config['HAS_LANGINFO'] = HAS_LANGINFO -dumpcache.dumpcache2('locale', config) diff --git a/lib_pypy/ctypes_config_cache/resource.ctc.py b/lib_pypy/ctypes_config_cache/resource.ctc.py --- a/lib_pypy/ctypes_config_cache/resource.ctc.py +++ b/lib_pypy/ctypes_config_cache/resource.ctc.py @@ -5,7 +5,6 @@ from ctypes import sizeof -import dumpcache from ctypes_configure.configure import (configure, ExternalCompilationInfo, ConstantInteger, DefinedConstantInteger, SimpleType) @@ -59,4 +58,3 @@ del config[key] config['ALL_CONSTANTS'] = _CONSTANTS + tuple(optional_constants) -dumpcache.dumpcache2('resource', config) diff --git a/lib_pypy/ctypes_config_cache/syslog.ctc.py b/lib_pypy/ctypes_config_cache/syslog.ctc.py --- a/lib_pypy/ctypes_config_cache/syslog.ctc.py +++ b/lib_pypy/ctypes_config_cache/syslog.ctc.py @@ -5,7 +5,6 @@ from ctypes_configure.configure import (configure, ExternalCompilationInfo, ConstantInteger, DefinedConstantInteger) -import dumpcache _CONSTANTS = ( @@ -72,4 +71,3 @@ all_constants = config.keys() all_constants.sort() config['ALL_CONSTANTS'] = tuple(all_constants) -dumpcache.dumpcache2('syslog', config) diff --git a/pypy/tool/lib_pypy.py b/pypy/tool/lib_pypy.py --- a/pypy/tool/lib_pypy.py +++ b/pypy/tool/lib_pypy.py @@ -1,11 +1,13 @@ import os import sys +from functools import partial import py import pypy import pypy.module from pypy.module.sys.version import CPYTHON_VERSION + from ctypes_configure import dumpcache from pypy.jit.backend import detect_cpu @@ -49,17 +51,12 @@ def rebuild_one(path): filename = str(path) d = {'__file__': filename} -#XXX: hack -class DumpCache: -@staticmethod -def dumpcache2(basename, config): -dumpcache2(basename, config, filename) - -sys.modules['dumpcache'] = DumpCache() try: execfile(filename, d) finally: -del sys.modules['dumpcache'] +base = path.basename.split('.')[0] +dumpcache2(base, d['config'], filename) + def try_rebuild(): from pypy.jit.backend import detect_cpu ___ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit