[pypy-commit] cffi release-0.8: hg merge default

arigo noreply at buildbot.pypy.org
Sat Jul 5 17:05:37 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: release-0.8
Changeset: r1535:1f0fc199c139
Date: 2014-07-05 16:47 +0200
http://bitbucket.org/cffi/cffi/changeset/1f0fc199c139/

Log:	hg merge default

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -5,7 +5,6 @@
 #ifdef MS_WIN32
 #include <windows.h>
 #include "misc_win32.h"
-#include <malloc.h>   /* for alloca() */
 #else
 #include <stddef.h>
 #include <stdint.h>
@@ -13,9 +12,32 @@
 #include <errno.h>
 #include <ffi.h>
 #include <sys/mman.h>
-#if (defined (__SVR4) && defined (__sun)) || defined(_AIX)
+#endif
+
+/* this block of #ifs should be kept exactly identical between
+   c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */
+#if defined(_MSC_VER)
+# include <malloc.h>   /* for alloca() */
+# if _MSC_VER < 1600   /* MSVC < 2010 */
+   typedef __int8 int8_t;
+   typedef __int16 int16_t;
+   typedef __int32 int32_t;
+   typedef __int64 int64_t;
+   typedef unsigned __int8 uint8_t;
+   typedef unsigned __int16 uint16_t;
+   typedef unsigned __int32 uint32_t;
+   typedef unsigned __int64 uint64_t;
+# else
+#  include <stdint.h>
+# endif
+# if _MSC_VER < 1800   /* MSVC < 2013 */
+   typedef unsigned char _Bool;
+# endif
+#else
+# include <stdint.h>
+# if (defined (__SVR4) && defined (__sun)) || defined(_AIX)
 #  include <alloca.h>
-#endif
+# endif
 #endif
 
 #include "malloc_closure.h"
@@ -5482,7 +5504,7 @@
     if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
         INITERROR;
 
-    v = PyText_FromString("0.8.2");
+    v = PyText_FromString("0.8.3");
     if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
         INITERROR;
 
diff --git a/c/check__thread.c b/c/check__thread.c
deleted file mode 100644
--- a/c/check__thread.c
+++ /dev/null
@@ -1,1 +0,0 @@
-__thread int some_threadlocal_variable_42;
diff --git a/c/minibuffer.h b/c/minibuffer.h
--- a/c/minibuffer.h
+++ b/c/minibuffer.h
@@ -105,8 +105,9 @@
 
 static int mb_getbuf(MiniBufferObj *self, Py_buffer *view, int flags)
 {
-    return PyBuffer_FillInfo(view, NULL, self->mb_data, self->mb_size,
-                             /*readonly=*/0, PyBUF_CONTIG | PyBUF_FORMAT);
+    return PyBuffer_FillInfo(view, (PyObject *)self,
+                             self->mb_data, self->mb_size,
+                             /*readonly=*/0, flags);
 }
 
 static PySequenceMethods mb_as_sequence = {
diff --git a/c/misc_win32.h b/c/misc_win32.h
--- a/c/misc_win32.h
+++ b/c/misc_win32.h
@@ -1,3 +1,4 @@
+#include <malloc.h>   /* for alloca() */
 
 /************************************************************/
 /* errno and GetLastError support */
@@ -192,7 +193,27 @@
 
 static void *dlsym(void *handle, const char *symbol)
 {
-    return GetProcAddress((HMODULE)handle, symbol);
+    void *address = GetProcAddress((HMODULE)handle, symbol);
+#ifndef MS_WIN64
+    if (!address) {
+        /* If 'symbol' is not found, then try '_symbol at N' for N in
+           (0, 4, 8, 12, ..., 124).  Unlike ctypes, we try to do that
+           for any symbol, although in theory it should only be done
+           for __stdcall functions.
+        */
+        int i;
+        char *mangled_name = alloca(1 + strlen(symbol) + 1 + 3 + 1);
+        if (!mangled_name)
+            return NULL;
+        for (i = 0; i < 32; i++) {
+            sprintf(mangled_name, "_%s@%d", symbol, i * 4);
+            address = GetProcAddress((HMODULE)handle, mangled_name);
+            if (address)
+                break;
+        }
+    }
+#endif
+    return address;
 }
 
 static void dlclose(void *handle)
@@ -210,21 +231,6 @@
     return buf;
 }
 
-
-/************************************************************/
-/* types */
-
-typedef __int8 int8_t;
-typedef __int16 int16_t;
-typedef __int32 int32_t;
-typedef __int64 int64_t;
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-typedef unsigned char _Bool;
-
-
 /************************************************************/
 /* obscure */
 
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1102,7 +1102,7 @@
 def test_read_variable():
     ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
     ## https://bugs.pypy.org/issue1643
-    if sys.platform == 'win32' or sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
+    if not sys.platform.startswith("linux"):
         py.test.skip("untested")
     BVoidP = new_pointer_type(new_void_type())
     ll = find_and_load_library('c')
@@ -1112,7 +1112,7 @@
 def test_read_variable_as_unknown_length_array():
     ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
     ## https://bugs.pypy.org/issue1643
-    if sys.platform == 'win32' or sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
+    if not sys.platform.startswith("linux"):
         py.test.skip("untested")
     BCharP = new_pointer_type(new_primitive_type("char"))
     BArray = new_array_type(BCharP, None)
@@ -1124,7 +1124,7 @@
 def test_write_variable():
     ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
     ## https://bugs.pypy.org/issue1643
-    if sys.platform == 'win32' or sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
+    if not sys.platform.startswith("linux"):
         py.test.skip("untested")
     BVoidP = new_pointer_type(new_void_type())
     ll = find_and_load_library('c')
@@ -3199,4 +3199,4 @@
 
 def test_version():
     # this test is here mostly for PyPy
-    assert __version__ == "0.8.2"
+    assert __version__ == "0.8.3"
diff --git a/cffi/__init__.py b/cffi/__init__.py
--- a/cffi/__init__.py
+++ b/cffi/__init__.py
@@ -4,5 +4,5 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "0.8.2"
-__version_info__ = (0, 8, 2)
+__version__ = "0.8.3"
+__version_info__ = (0, 8, 3)
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -443,6 +443,10 @@
                 for enumname, enumval in zip(tp.enumerators, tp.enumvalues):
                     if enumname not in library.__dict__:
                         library.__dict__[enumname] = enumval
+            for key, val in ffi._parser._int_constants.items():
+                if key not in library.__dict__:
+                    library.__dict__[key] = val
+
             copied_enums.append(True)
             if name in library.__dict__:
                 return
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -24,6 +24,7 @@
 _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]")
 _r_words = re.compile(r"\w+|\S")
 _parser_cache = None
+_r_int_literal = re.compile(r"^0?x?[0-9a-f]+u?l?$", re.IGNORECASE)
 
 def _get_parser():
     global _parser_cache
@@ -99,6 +100,7 @@
         self._structnode2type = weakref.WeakKeyDictionary()
         self._override = False
         self._packed = False
+        self._int_constants = {}
 
     def _parse(self, csource):
         csource, macros = _preprocess(csource)
@@ -128,9 +130,10 @@
         finally:
             if lock is not None:
                 lock.release()
-        return ast, macros
+        # csource will be used to find buggy source text
+        return ast, macros, csource
 
-    def convert_pycparser_error(self, e, csource):
+    def _convert_pycparser_error(self, e, csource):
         # xxx look for ":NUM:" at the start of str(e) and try to interpret
         # it as a line number
         line = None
@@ -142,6 +145,12 @@
                 csourcelines = csource.splitlines()
                 if 1 <= linenum <= len(csourcelines):
                     line = csourcelines[linenum-1]
+        return line
+
+    def convert_pycparser_error(self, e, csource):
+        line = self._convert_pycparser_error(e, csource)
+
+        msg = str(e)
         if line:
             msg = 'cannot parse "%s"\n%s' % (line.strip(), msg)
         else:
@@ -160,14 +169,9 @@
             self._packed = prev_packed
 
     def _internal_parse(self, csource):
-        ast, macros = self._parse(csource)
+        ast, macros, csource = self._parse(csource)
         # add the macros
-        for key, value in macros.items():
-            value = value.strip()
-            if value != '...':
-                raise api.CDefError('only supports the syntax "#define '
-                                    '%s ..." for now (literally)' % key)
-            self._declare('macro ' + key, value)
+        self._process_macros(macros)
         # find the first "__dotdotdot__" and use that as a separator
         # between the repeated typedefs and the real csource
         iterator = iter(ast.ext)
@@ -175,27 +179,61 @@
             if decl.name == '__dotdotdot__':
                 break
         #
-        for decl in iterator:
-            if isinstance(decl, pycparser.c_ast.Decl):
-                self._parse_decl(decl)
-            elif isinstance(decl, pycparser.c_ast.Typedef):
-                if not decl.name:
-                    raise api.CDefError("typedef does not declare any name",
-                                        decl)
-                if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType)
-                        and decl.type.type.names == ['__dotdotdot__']):
-                    realtype = model.unknown_type(decl.name)
-                elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and
-                      isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and
-                      isinstance(decl.type.type.type,
-                                 pycparser.c_ast.IdentifierType) and
-                      decl.type.type.type.names == ['__dotdotdot__']):
-                    realtype = model.unknown_ptr_type(decl.name)
+        try:
+            for decl in iterator:
+                if isinstance(decl, pycparser.c_ast.Decl):
+                    self._parse_decl(decl)
+                elif isinstance(decl, pycparser.c_ast.Typedef):
+                    if not decl.name:
+                        raise api.CDefError("typedef does not declare any name",
+                                            decl)
+                    if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType)
+                            and decl.type.type.names == ['__dotdotdot__']):
+                        realtype = model.unknown_type(decl.name)
+                    elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and
+                          isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and
+                          isinstance(decl.type.type.type,
+                                     pycparser.c_ast.IdentifierType) and
+                          decl.type.type.type.names == ['__dotdotdot__']):
+                        realtype = model.unknown_ptr_type(decl.name)
+                    else:
+                        realtype = self._get_type(decl.type, name=decl.name)
+                    self._declare('typedef ' + decl.name, realtype)
                 else:
-                    realtype = self._get_type(decl.type, name=decl.name)
-                self._declare('typedef ' + decl.name, realtype)
+                    raise api.CDefError("unrecognized construct", decl)
+        except api.FFIError as e:
+            msg = self._convert_pycparser_error(e, csource)
+            if msg:
+                e.args = (e.args[0] + "\n    *** Err: %s" % msg,)
+            raise
+
+    def _add_constants(self, key, val):
+        if key in self._int_constants:
+            raise api.FFIError(
+                "multiple declarations of constant: %s" % (key,))
+        self._int_constants[key] = val
+
+    def _process_macros(self, macros):
+        for key, value in macros.items():
+            value = value.strip()
+            match = _r_int_literal.search(value)
+            if match is not None:
+                int_str = match.group(0).lower().rstrip("ul")
+
+                # "010" is not valid oct in py3
+                if (int_str.startswith("0") and
+                        int_str != "0" and
+                        not int_str.startswith("0x")):
+                    int_str = "0o" + int_str[1:]
+
+                pyvalue = int(int_str, 0)
+                self._add_constants(key, pyvalue)
+            elif value == '...':
+                self._declare('macro ' + key, value)
             else:
-                raise api.CDefError("unrecognized construct", decl)
+                raise api.CDefError('only supports the syntax "#define '
+                                    '%s ..." (literally) or "#define '
+                                    '%s 0x1FF" for now' % (key, key))
 
     def _parse_decl(self, decl):
         node = decl.type
@@ -227,7 +265,7 @@
                     self._declare('variable ' + decl.name, tp)
 
     def parse_type(self, cdecl):
-        ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)
+        ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2]
         assert not macros
         exprnode = ast.ext[-1].type.args.params[0]
         if isinstance(exprnode, pycparser.c_ast.ID):
@@ -306,7 +344,8 @@
                 if ident == 'void':
                     return model.void_type
                 if ident == '__dotdotdot__':
-                    raise api.FFIError('bad usage of "..."')
+                    raise api.FFIError(':%d: bad usage of "..."' %
+                            typenode.coord.line)
                 return resolve_common_type(ident)
             #
             if isinstance(type, pycparser.c_ast.Struct):
@@ -333,7 +372,8 @@
             return self._get_struct_union_enum_type('union', typenode, name,
                                                     nested=True)
         #
-        raise api.FFIError("bad or unsupported type declaration")
+        raise api.FFIError(":%d: bad or unsupported type declaration" %
+                typenode.coord.line)
 
     def _parse_function_type(self, typenode, funcname=None):
         params = list(getattr(typenode.args, 'params', []))
@@ -499,6 +539,10 @@
         if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
                 exprnode.op == '-'):
             return -self._parse_constant(exprnode.expr)
+        # load previously defined int constant
+        if (isinstance(exprnode, pycparser.c_ast.ID) and
+                exprnode.name in self._int_constants):
+            return self._int_constants[exprnode.name]
         #
         if partial_length_ok:
             if (isinstance(exprnode, pycparser.c_ast.ID) and
@@ -506,8 +550,8 @@
                 self._partial_length = True
                 return '...'
         #
-        raise api.FFIError("unsupported expression: expected a "
-                           "simple numeric constant")
+        raise api.FFIError(":%d: unsupported expression: expected a "
+                           "simple numeric constant" % exprnode.coord.line)
 
     def _build_enum_type(self, explicit_name, decls):
         if decls is not None:
@@ -522,6 +566,7 @@
                 if enum.value is not None:
                     nextenumvalue = self._parse_constant(enum.value)
                 enumvalues.append(nextenumvalue)
+                self._add_constants(enum.name, nextenumvalue)
                 nextenumvalue += 1
             enumvalues = tuple(enumvalues)
             tp = model.EnumType(explicit_name, enumerators, enumvalues)
@@ -535,3 +580,5 @@
             kind = name.split(' ', 1)[0]
             if kind in ('typedef', 'struct', 'union', 'enum'):
                 self._declare(name, tp)
+        for k, v in other._int_constants.items():
+            self._add_constants(k, v)
diff --git a/cffi/ffiplatform.py b/cffi/ffiplatform.py
--- a/cffi/ffiplatform.py
+++ b/cffi/ffiplatform.py
@@ -38,6 +38,7 @@
     import distutils.errors
     #
     dist = Distribution({'ext_modules': [ext]})
+    dist.parse_config_files()
     options = dist.get_option_dict('build_ext')
     options['force'] = ('ffiplatform', True)
     options['build_lib'] = ('ffiplatform', tmpdir)
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -89,43 +89,54 @@
         # by generate_cpy_function_method().
         prnt('static PyMethodDef _cffi_methods[] = {')
         self._generate("method")
-        prnt('  {"_cffi_setup", _cffi_setup, METH_VARARGS},')
-        prnt('  {NULL, NULL}    /* Sentinel */')
+        prnt('  {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},')
+        prnt('  {NULL, NULL, 0, NULL}    /* Sentinel */')
         prnt('};')
         prnt()
         #
         # standard init.
         modname = self.verifier.get_module_name()
-        if sys.version_info >= (3,):
-            prnt('static struct PyModuleDef _cffi_module_def = {')
-            prnt('  PyModuleDef_HEAD_INIT,')
-            prnt('  "%s",' % modname)
-            prnt('  NULL,')
-            prnt('  -1,')
-            prnt('  _cffi_methods,')
-            prnt('  NULL, NULL, NULL, NULL')
-            prnt('};')
-            prnt()
-            initname = 'PyInit_%s' % modname
-            createmod = 'PyModule_Create(&_cffi_module_def)'
-            errorcase = 'return NULL'
-            finalreturn = 'return lib'
-        else:
-            initname = 'init%s' % modname
-            createmod = 'Py_InitModule("%s", _cffi_methods)' % modname
-            errorcase = 'return'
-            finalreturn = 'return'
+        constants = self._chained_list_constants[False]
+        prnt('#if PY_MAJOR_VERSION >= 3')
+        prnt()
+        prnt('static struct PyModuleDef _cffi_module_def = {')
+        prnt('  PyModuleDef_HEAD_INIT,')
+        prnt('  "%s",' % modname)
+        prnt('  NULL,')
+        prnt('  -1,')
+        prnt('  _cffi_methods,')
+        prnt('  NULL, NULL, NULL, NULL')
+        prnt('};')
+        prnt()
         prnt('PyMODINIT_FUNC')
-        prnt('%s(void)' % initname)
+        prnt('PyInit_%s(void)' % modname)
         prnt('{')
         prnt('  PyObject *lib;')
-        prnt('  lib = %s;' % createmod)
-        prnt('  if (lib == NULL || %s < 0)' % (
-            self._chained_list_constants[False],))
-        prnt('    %s;' % errorcase)
-        prnt('  _cffi_init();')
-        prnt('  %s;' % finalreturn)
+        prnt('  lib = PyModule_Create(&_cffi_module_def);')
+        prnt('  if (lib == NULL)')
+        prnt('    return NULL;')
+        prnt('  if (%s < 0 || _cffi_init() < 0) {' % (constants,))
+        prnt('    Py_DECREF(lib);')
+        prnt('    return NULL;')
+        prnt('  }')
+        prnt('  return lib;')
         prnt('}')
+        prnt()
+        prnt('#else')
+        prnt()
+        prnt('PyMODINIT_FUNC')
+        prnt('init%s(void)' % modname)
+        prnt('{')
+        prnt('  PyObject *lib;')
+        prnt('  lib = Py_InitModule("%s", _cffi_methods);' % modname)
+        prnt('  if (lib == NULL)')
+        prnt('    return;')
+        prnt('  if (%s < 0 || _cffi_init() < 0)' % (constants,))
+        prnt('    return;')
+        prnt('  return;')
+        prnt('}')
+        prnt()
+        prnt('#endif')
 
     def load_library(self):
         # XXX review all usages of 'self' here!
@@ -394,7 +405,7 @@
             meth = 'METH_O'
         else:
             meth = 'METH_VARARGS'
-        self._prnt('  {"%s", _cffi_f_%s, %s},' % (name, name, meth))
+        self._prnt('  {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth))
 
     _loading_cpy_function = _loaded_noop
 
@@ -481,8 +492,8 @@
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
         layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
-        self._prnt('  {"%s", %s, METH_NOARGS},' % (layoutfuncname,
-                                                   layoutfuncname))
+        self._prnt('  {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname,
+                                                         layoutfuncname))
 
     def _loading_struct_or_union(self, tp, prefix, name, module):
         if tp.fldnames is None:
@@ -589,13 +600,7 @@
                                                           'variable type'),))
             assert delayed
         else:
-            prnt('  if (LONG_MIN <= (%s) && (%s) <= LONG_MAX)' % (name, name))
-            prnt('    o = PyInt_FromLong((long)(%s));' % (name,))
-            prnt('  else if ((%s) <= 0)' % (name,))
-            prnt('    o = PyLong_FromLongLong((long long)(%s));' % (name,))
-            prnt('  else')
-            prnt('    o = PyLong_FromUnsignedLongLong('
-                 '(unsigned long long)(%s));' % (name,))
+            prnt('  o = _cffi_from_c_int_const(%s);' % name)
         prnt('  if (o == NULL)')
         prnt('    return -1;')
         if size_too:
@@ -632,13 +637,18 @@
     # ----------
     # enums
 
+    def _enum_funcname(self, prefix, name):
+        # "$enum_$1" => "___D_enum____D_1"
+        name = name.replace('$', '___D_')
+        return '_cffi_e_%s_%s' % (prefix, name)
+
     def _generate_cpy_enum_decl(self, tp, name, prefix='enum'):
         if tp.partial:
             for enumerator in tp.enumerators:
                 self._generate_cpy_const(True, enumerator, delayed=False)
             return
         #
-        funcname = '_cffi_e_%s_%s' % (prefix, name)
+        funcname = self._enum_funcname(prefix, name)
         prnt = self._prnt
         prnt('static int %s(PyObject *lib)' % funcname)
         prnt('{')
@@ -760,17 +770,30 @@
 #include <Python.h>
 #include <stddef.h>
 
-#ifdef MS_WIN32
-#include <malloc.h>   /* for alloca() */
-typedef __int8 int8_t;
-typedef __int16 int16_t;
-typedef __int32 int32_t;
-typedef __int64 int64_t;
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-typedef unsigned char _Bool;
+/* this block of #ifs should be kept exactly identical between
+   c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */
+#if defined(_MSC_VER)
+# include <malloc.h>   /* for alloca() */
+# if _MSC_VER < 1600   /* MSVC < 2010 */
+   typedef __int8 int8_t;
+   typedef __int16 int16_t;
+   typedef __int32 int32_t;
+   typedef __int64 int64_t;
+   typedef unsigned __int8 uint8_t;
+   typedef unsigned __int16 uint16_t;
+   typedef unsigned __int32 uint32_t;
+   typedef unsigned __int64 uint64_t;
+# else
+#  include <stdint.h>
+# endif
+# if _MSC_VER < 1800   /* MSVC < 2013 */
+   typedef unsigned char _Bool;
+# endif
+#else
+# include <stdint.h>
+# if (defined (__SVR4) && defined (__sun)) || defined(_AIX)
+#  include <alloca.h>
+# endif
 #endif
 
 #if PY_MAJOR_VERSION < 3
@@ -795,6 +818,15 @@
 #define _cffi_to_c_double PyFloat_AsDouble
 #define _cffi_to_c_float PyFloat_AsDouble
 
+#define _cffi_from_c_int_const(x)                                        \
+    (((x) > 0) ?                                                         \
+        ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ?      \
+            PyInt_FromLong((long)(x)) :                                  \
+            PyLong_FromUnsignedLongLong((unsigned long long)(x)) :       \
+        ((long long)(x) >= (long long)LONG_MIN) ?                        \
+            PyInt_FromLong((long)(x)) :                                  \
+            PyLong_FromLongLong((long long)(x)))
+
 #define _cffi_from_c_int(x, type)                                        \
     (((type)-1) > 0 ?   /* unsigned */                                   \
         (sizeof(type) < sizeof(long) ? PyInt_FromLong(x) :               \
@@ -804,14 +836,14 @@
                                         PyLong_FromLongLong(x)))
 
 #define _cffi_to_c_int(o, type)                                          \
-    (sizeof(type) == 1 ? (((type)-1) > 0 ? _cffi_to_c_u8(o)              \
-                                         : _cffi_to_c_i8(o)) :           \
-     sizeof(type) == 2 ? (((type)-1) > 0 ? _cffi_to_c_u16(o)             \
-                                         : _cffi_to_c_i16(o)) :          \
-     sizeof(type) == 4 ? (((type)-1) > 0 ? _cffi_to_c_u32(o)             \
-                                         : _cffi_to_c_i32(o)) :          \
-     sizeof(type) == 8 ? (((type)-1) > 0 ? _cffi_to_c_u64(o)             \
-                                         : _cffi_to_c_i64(o)) :          \
+    (sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o)        \
+                                         : (type)_cffi_to_c_i8(o)) :     \
+     sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o)       \
+                                         : (type)_cffi_to_c_i16(o)) :    \
+     sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o)       \
+                                         : (type)_cffi_to_c_i32(o)) :    \
+     sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o)       \
+                                         : (type)_cffi_to_c_i64(o)) :    \
      (Py_FatalError("unsupported size for type " #type), 0))
 
 #define _cffi_to_c_i8                                                    \
@@ -885,25 +917,32 @@
     return PyBool_FromLong(was_alive);
 }
 
-static void _cffi_init(void)
+static int _cffi_init(void)
 {
-    PyObject *module = PyImport_ImportModule("_cffi_backend");
-    PyObject *c_api_object;
+    PyObject *module, *c_api_object = NULL;
 
+    module = PyImport_ImportModule("_cffi_backend");
     if (module == NULL)
-        return;
+        goto failure;
 
     c_api_object = PyObject_GetAttrString(module, "_C_API");
     if (c_api_object == NULL)
-        return;
+        goto failure;
     if (!PyCapsule_CheckExact(c_api_object)) {
-        Py_DECREF(c_api_object);
         PyErr_SetNone(PyExc_ImportError);
-        return;
+        goto failure;
     }
     memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"),
            _CFFI_NUM_EXPORTS * sizeof(void *));
+
+    Py_DECREF(module);
     Py_DECREF(c_api_object);
+    return 0;
+
+  failure:
+    Py_XDECREF(module);
+    Py_XDECREF(c_api_object);
+    return -1;
 }
 
 #define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num))
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
--- a/cffi/vengine_gen.py
+++ b/cffi/vengine_gen.py
@@ -249,10 +249,10 @@
                     prnt('  /* %s */' % str(e))   # cannot verify it, ignore
         prnt('}')
         self.export_symbols.append(layoutfuncname)
-        prnt('ssize_t %s(ssize_t i)' % (layoutfuncname,))
+        prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,))
         prnt('{')
         prnt('  struct _cffi_aligncheck { char x; %s y; };' % cname)
-        prnt('  static ssize_t nums[] = {')
+        prnt('  static intptr_t nums[] = {')
         prnt('    sizeof(%s),' % cname)
         prnt('    offsetof(struct _cffi_aligncheck, y),')
         for fname, ftype, fbitsize in tp.enumfields():
@@ -276,7 +276,7 @@
             return     # nothing to do with opaque structs
         layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
         #
-        BFunc = self.ffi._typeof_locked("ssize_t(*)(ssize_t)")[0]
+        BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0]
         function = module.load_function(BFunc, layoutfuncname)
         layout = []
         num = 0
@@ -410,13 +410,18 @@
     # ----------
     # enums
 
+    def _enum_funcname(self, prefix, name):
+        # "$enum_$1" => "___D_enum____D_1"
+        name = name.replace('$', '___D_')
+        return '_cffi_e_%s_%s' % (prefix, name)
+
     def _generate_gen_enum_decl(self, tp, name, prefix='enum'):
         if tp.partial:
             for enumerator in tp.enumerators:
                 self._generate_gen_const(True, enumerator)
             return
         #
-        funcname = '_cffi_e_%s_%s' % (prefix, name)
+        funcname = self._enum_funcname(prefix, name)
         self.export_symbols.append(funcname)
         prnt = self._prnt
         prnt('int %s(char *out_error)' % funcname)
@@ -453,7 +458,7 @@
         else:
             BType = self.ffi._typeof_locked("char[]")[0]
             BFunc = self.ffi._typeof_locked("int(*)(char*)")[0]
-            funcname = '_cffi_e_%s_%s' % (prefix, name)
+            funcname = self._enum_funcname(prefix, name)
             function = module.load_function(BFunc, funcname)
             p = self.ffi.new(BType, 256)
             if function(p) < 0:
@@ -547,20 +552,29 @@
 #include <errno.h>
 #include <sys/types.h>   /* XXX for ssize_t on some platforms */
 
-#ifdef _WIN32
-#  include <Windows.h>
-#  define snprintf _snprintf
-typedef __int8 int8_t;
-typedef __int16 int16_t;
-typedef __int32 int32_t;
-typedef __int64 int64_t;
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-typedef SSIZE_T ssize_t;
-typedef unsigned char _Bool;
+/* this block of #ifs should be kept exactly identical between
+   c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */
+#if defined(_MSC_VER)
+# include <malloc.h>   /* for alloca() */
+# if _MSC_VER < 1600   /* MSVC < 2010 */
+   typedef __int8 int8_t;
+   typedef __int16 int16_t;
+   typedef __int32 int32_t;
+   typedef __int64 int64_t;
+   typedef unsigned __int8 uint8_t;
+   typedef unsigned __int16 uint16_t;
+   typedef unsigned __int32 uint32_t;
+   typedef unsigned __int64 uint64_t;
+# else
+#  include <stdint.h>
+# endif
+# if _MSC_VER < 1800   /* MSVC < 2013 */
+   typedef unsigned char _Bool;
+# endif
 #else
-#  include <stdint.h>
+# include <stdint.h>
+# if (defined (__SVR4) && defined (__sun)) || defined(_AIX)
+#  include <alloca.h>
+# endif
 #endif
 '''
diff --git a/doc/source/conf.py b/doc/source/conf.py
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -47,7 +47,7 @@
 # The short X.Y version.
 version = '0.8'
 # The full version, including alpha/beta/rc tags.
-release = '0.8.2'
+release = '0.8.3'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -1,31 +1,34 @@
 CFFI documentation
 ================================
 
-Foreign Function Interface for Python calling C code. The aim of this project
-is to provide a convenient and reliable way of calling C code from Python.
-The interface is based on `LuaJIT's FFI`_ and follows a few principles:
+C Foreign Function Interface for Python. The goal is to provide a
+convenient and reliable way to call compiled C code from Python using
+interface declarations written in C.
 
-* The goal is to call C code from Python.  You should be able to do so
-  without learning a 3rd language: every alternative requires you to learn
-  their own language (Cython_, SWIG_) or API (ctypes_).  So we tried to
-  assume that you know Python and C and minimize the extra bits of API that
-  you need to learn.
+The interface is based on `LuaJIT's FFI`_, and follows a few principles:
+
+* The goal is to call C code from Python without learning a 3rd language:
+  existing alternatives require users to learn domain specific language
+  (Cython_, SWIG_) or API (ctypes_). The CFFI design requires users to know
+  only C and Python, minimizing the extra bits of API that need to be learned.
 
 * Keep all the Python-related logic in Python so that you don't need to
   write much C code (unlike `CPython native C extensions`_).
 
-* Work either at the level of the ABI (Application Binary Interface)
-  or the API (Application Programming Interface).  Usually, C
-  libraries have a specified C API but often not an ABI (e.g. they may
+* The preferred way is to work at the level of the API (Application
+  Programming Interface): the C compiler is called from the declarations
+  you write to validate and link to the C language constructs.
+  Alternatively, it is also possible to work at the ABI level
+  (Application Binary Interface), the way ctypes_ work.
+  However, on non-Windows platforms, C libraries typically
+  have a specified C API but not an ABI (e.g. they may
   document a "struct" as having at least these fields, but maybe more).
-  (ctypes_ works at the ABI level, whereas Cython_ and `native C extensions`_
-  work at the API level.)
 
-* We try to be complete.  For now some C99 constructs are not supported,
+* Try to be complete.  For now some C99 constructs are not supported,
   but all C89 should be, including macros (and including macro "abuses",
   which you can `manually wrap`_ in saner-looking C functions).
 
-* We attempt to support both PyPy and CPython, with a reasonable path
+* Attempt to support both PyPy and CPython, with a reasonable path
   for other Python implementations like IronPython and Jython.
 
 * Note that this project is **not** about embedding executable C code in
@@ -38,7 +41,7 @@
 .. _`CPython native C extensions`: http://docs.python.org/extending/extending.html
 .. _`native C extensions`: http://docs.python.org/extending/extending.html
 .. _`ctypes`: http://docs.python.org/library/ctypes.html
-.. _`Weave`: http://www.scipy.org/Weave
+.. _`Weave`: http://wiki.scipy.org/Weave
 .. _`manually wrap`: `The verification step`_
 
 
@@ -85,13 +88,13 @@
 
 Download and Installation:
 
-* http://pypi.python.org/packages/source/c/cffi/cffi-0.8.2.tar.gz
+* http://pypi.python.org/packages/source/c/cffi/cffi-0.8.3.tar.gz
 
    - Or grab the most current version by following the instructions below.
 
-   - MD5: 37fc88c62f40d04e8a18192433f951ec
+   - MD5: ...
 
-   - SHA: 75a6c433664a7a38d4d03cecbdc72cef4c3cceac
+   - SHA: ...
 
 * Or get it from the `Bitbucket page`_:
   ``hg clone https://bitbucket.org/cffi/cffi``
@@ -851,7 +854,7 @@
 ``ffi`` normally caches the string ``"int[]"`` to not need to re-parse
 it all the time.
 
-.. versionadded:: 0.9
+.. versionadded:: 0.8.2
    The ``ffi.cdef()`` call takes an optional argument ``packed``: if
    True, then all structs declared within this cdef are "packed".  This
    has a meaning similar to ``__attribute__((packed))`` in GCC.  It
@@ -1195,13 +1198,14 @@
    owned memory will not be freed as long as the buffer is alive.
    Moreover buffer objects now support weakrefs to them.
 
-.. versionchanged:: 0.9
-   Before version 0.9, ``bytes(buf)`` was supported in Python 3 to get
+.. versionchanged:: 0.8.2
+   Before version 0.8.2, ``bytes(buf)`` was supported in Python 3 to get
    the content of the buffer, but on Python 2 it would return the repr
    ``<_cffi_backend.buffer object>``.  This has been fixed.  But you
    should avoid using ``str(buf)``: it now gives inconsistent results
    between Python 2 and Python 3 (this is similar to how ``str()``
-   gives inconsistent results on regular byte strings).
+   gives inconsistent results on regular byte strings).  Use ``buf[:]``
+   instead.
 
 
 ``ffi.typeof("C type" or cdata object)``: return an object of type
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -42,25 +42,14 @@
             resultlist[:] = res
 
 def ask_supports_thread():
-    if sys.platform == "darwin":
-        sys.stderr.write("OS/X: confusion between 'cc' versus 'gcc'")
-        sys.stderr.write(" (see issue 123)\n")
-        sys.stderr.write("will not use '__thread' in the C code\n")
-        return
-    import distutils.errors
-    from distutils.ccompiler import new_compiler
-    compiler = new_compiler(force=1)
-    try:
-        compiler.compile(['c/check__thread.c'])
-    except distutils.errors.CompileError:
-        sys.stderr.write("the above error message can be safely ignored;\n")
-        sys.stderr.write("will not use '__thread' in the C code\n")
+    from distutils.core import Distribution
+    config = Distribution().get_command_obj('config')
+    ok = config.try_compile('__thread int some_threadlocal_variable_42;')
+    if ok:
+        define_macros.append(('USE__THREAD', None))
     else:
-        define_macros.append(('USE__THREAD', None))
-    try:
-        os.unlink('c/check__thread.o')
-    except OSError:
-        pass
+        sys.stderr.write("Note: will not use '__thread' in the C code\n")
+        sys.stderr.write("The above error message can be safely ignored\n")
 
 def use_pkg_config():
     _ask_pkg_config(include_dirs,       '--cflags-only-I', '-I', sysroot=True)
@@ -124,7 +113,7 @@
 
 `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
 """,
-        version='0.8.2',
+        version='0.8.3',
         packages=['cffi'],
         zip_safe=False,
 
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -865,25 +865,25 @@
 
     def test_enum(self):
         ffi = FFI(backend=self.Backend())
-        ffi.cdef("enum foo { A, B, CC, D };")
-        assert ffi.string(ffi.cast("enum foo", 0)) == "A"
-        assert ffi.string(ffi.cast("enum foo", 2)) == "CC"
-        assert ffi.string(ffi.cast("enum foo", 3)) == "D"
+        ffi.cdef("enum foo { A0, B0, CC0, D0 };")
+        assert ffi.string(ffi.cast("enum foo", 0)) == "A0"
+        assert ffi.string(ffi.cast("enum foo", 2)) == "CC0"
+        assert ffi.string(ffi.cast("enum foo", 3)) == "D0"
         assert ffi.string(ffi.cast("enum foo", 4)) == "4"
-        ffi.cdef("enum bar { A, B=-2, CC, D, E };")
-        assert ffi.string(ffi.cast("enum bar", 0)) == "A"
-        assert ffi.string(ffi.cast("enum bar", -2)) == "B"
-        assert ffi.string(ffi.cast("enum bar", -1)) == "CC"
-        assert ffi.string(ffi.cast("enum bar", 1)) == "E"
+        ffi.cdef("enum bar { A1, B1=-2, CC1, D1, E1 };")
+        assert ffi.string(ffi.cast("enum bar", 0)) == "A1"
+        assert ffi.string(ffi.cast("enum bar", -2)) == "B1"
+        assert ffi.string(ffi.cast("enum bar", -1)) == "CC1"
+        assert ffi.string(ffi.cast("enum bar", 1)) == "E1"
         assert ffi.cast("enum bar", -2) != ffi.cast("enum bar", -2)
         assert ffi.cast("enum foo", 0) != ffi.cast("enum bar", 0)
         assert ffi.cast("enum bar", 0) != ffi.cast("int", 0)
-        assert repr(ffi.cast("enum bar", -1)) == "<cdata 'enum bar' -1: CC>"
+        assert repr(ffi.cast("enum bar", -1)) == "<cdata 'enum bar' -1: CC1>"
         assert repr(ffi.cast("enum foo", -1)) == (  # enums are unsigned, if
             "<cdata 'enum foo' 4294967295>")        # they contain no neg value
-        ffi.cdef("enum baz { A=0x1000, B=0x2000 };")
-        assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A"
-        assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B"
+        ffi.cdef("enum baz { A2=0x1000, B2=0x2000 };")
+        assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A2"
+        assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2"
 
     def test_enum_in_struct(self):
         ffi = FFI(backend=self.Backend())
@@ -1322,6 +1322,16 @@
         e = ffi.cast("enum e", 0)
         assert ffi.string(e) == "AA"     # pick the first one arbitrarily
 
+    def test_enum_refer_previous_enum_value(self):
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("enum e { AA, BB=2, CC=4, DD=BB, EE, FF=CC, GG=FF };")
+        assert ffi.string(ffi.cast("enum e", 2)) == "BB"
+        assert ffi.string(ffi.cast("enum e", 3)) == "EE"
+        assert ffi.sizeof("char[DD]") == 2
+        assert ffi.sizeof("char[EE]") == 3
+        assert ffi.sizeof("char[FF]") == 4
+        assert ffi.sizeof("char[GG]") == 4
+
     def test_nested_anonymous_struct(self):
         ffi = FFI(backend=self.Backend())
         ffi.cdef("""
@@ -1543,6 +1553,7 @@
         ffi2.include(ffi1)
         p = ffi2.cast("enum foo", 1)
         assert ffi2.string(p) == "FB"
+        assert ffi2.sizeof("char[FC]") == 2
 
     def test_include_typedef_2(self):
         backend = self.Backend()
@@ -1570,3 +1581,25 @@
         assert s[0].a == b'X'
         assert s[1].b == -4892220
         assert s[1].a == b'Y'
+
+    def test_define_integer_constant(self):
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("""
+            #define DOT_0 0
+            #define DOT 100
+            #define DOT_OCT 0100l
+            #define DOT_HEX 0x100u
+            #define DOT_HEX2 0X10
+            #define DOT_UL 1000UL
+            enum foo {AA, BB=DOT, CC};
+        """)
+        lib = ffi.dlopen(None)
+        assert ffi.string(ffi.cast("enum foo", 100)) == "BB"
+        assert lib.DOT_0 == 0
+        assert lib.DOT == 100
+        assert lib.DOT_OCT == 0o100
+        assert lib.DOT_HEX == 0x100
+        assert lib.DOT_HEX2 == 0x10
+        assert lib.DOT_UL == 1000
+
+
diff --git a/testing/test_function.py b/testing/test_function.py
--- a/testing/test_function.py
+++ b/testing/test_function.py
@@ -402,3 +402,18 @@
             if wr() is not None:
                 import gc; gc.collect()
         assert wr() is None    # 'data' does not leak
+
+    def test_windows_stdcall(self):
+        if sys.platform != 'win32':
+            py.test.skip("Windows-only test")
+        if self.Backend is CTypesBackend:
+            py.test.skip("not with the ctypes backend")
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("""
+            BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
+        """)
+        m = ffi.dlopen("Kernel32.dll")
+        p_freq = ffi.new("LONGLONG *")
+        res = m.QueryPerformanceFrequency(p_freq)
+        assert res != 0
+        assert p_freq[0] != 0
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -161,9 +161,10 @@
 
 def test_define_not_supported_for_now():
     ffi = FFI(backend=FakeBackend())
-    e = py.test.raises(CDefError, ffi.cdef, "#define FOO 42")
-    assert str(e.value) == \
-           'only supports the syntax "#define FOO ..." for now (literally)'
+    e = py.test.raises(CDefError, ffi.cdef, '#define FOO "blah"')
+    assert str(e.value) == (
+        'only supports the syntax "#define FOO ..." (literally)'
+        ' or "#define FOO 0x1FF" for now')
 
 def test_unnamed_struct():
     ffi = FFI(backend=FakeBackend())
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -1,4 +1,4 @@
-import py
+import py, re
 import sys, os, math, weakref
 from cffi import FFI, VerificationError, VerificationMissing, model
 from testing.support import *
@@ -29,6 +29,24 @@
 def setup_module():
     import cffi.verifier
     cffi.verifier.cleanup_tmpdir()
+    #
+    # check that no $ sign is produced in the C file; it used to be the
+    # case that anonymous enums would produce '$enum_$1', which was
+    # used as part of a function name.  GCC accepts such names, but it's
+    # apparently non-standard.
+    _r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE)
+    _r_string = re.compile(r'\".*?\"')
+    def _write_source_and_check(self, file=None):
+        base_write_source(self, file)
+        if file is None:
+            f = open(self.sourcefilename)
+            data = f.read()
+            f.close()
+            data = _r_comment.sub(' ', data)
+            data = _r_string.sub('"skipped"', data)
+            assert '$' not in data
+    base_write_source = cffi.verifier.Verifier._write_source
+    cffi.verifier.Verifier._write_source = _write_source_and_check
 
 
 def test_module_type():
@@ -153,6 +171,9 @@
 
 
 all_primitive_types = model.PrimitiveType.ALL_PRIMITIVE_TYPES
+if sys.platform == 'win32':
+    all_primitive_types = all_primitive_types.copy()
+    del all_primitive_types['ssize_t']
 all_integer_types = sorted(tp for tp in all_primitive_types
                            if all_primitive_types[tp] == 'i')
 all_float_types = sorted(tp for tp in all_primitive_types
@@ -1452,8 +1473,8 @@
     assert func() == 42
 
 def test_FILE_stored_in_stdout():
-    if sys.platform == 'win32':
-        py.test.skip("MSVC: cannot assign to stdout")
+    if not sys.platform.startswith('linux'):
+        py.test.skip("likely, we cannot assign to stdout")
     ffi = FFI()
     ffi.cdef("int printf(const char *, ...); FILE *setstdout(FILE *);")
     lib = ffi.verify("""
@@ -1636,8 +1657,8 @@
     ffi = FFI()
     ffi.cdef("""
         int (*python_callback)(int how_many, int *values);
-        void *const c_callback;   /* pass this ptr to C routines */
-        int some_c_function(void *cb);
+        int (*const c_callback)(int,...);   /* pass this ptr to C routines */
+        int some_c_function(int(*cb)(int,...));
     """)
     lib = ffi.verify("""
         #include <stdarg.h>
@@ -1884,3 +1905,60 @@
     p = lib.f2(42)
     x = lib.f1(p)
     assert x == 42
+
+def _run_in_multiple_threads(test1):
+    test1()
+    import sys
+    try:
+        import thread
+    except ImportError:
+        import _thread as thread
+    errors = []
+    def wrapper(lock):
+        try:
+            test1()
+        except:
+            errors.append(sys.exc_info())
+        lock.release()
+    locks = []
+    for i in range(10):
+        _lock = thread.allocate_lock()
+        _lock.acquire()
+        thread.start_new_thread(wrapper, (_lock,))
+        locks.append(_lock)
+    for _lock in locks:
+        _lock.acquire()
+        if errors:
+            raise errors[0][1]
+
+def test_errno_working_even_with_pypys_jit():
+    ffi = FFI()
+    ffi.cdef("int f(int);")
+    lib = ffi.verify("""
+        #include <errno.h>
+        int f(int x) { return (errno = errno + x); }
+    """)
+    @_run_in_multiple_threads
+    def test1():
+        ffi.errno = 0
+        for i in range(10000):
+            e = lib.f(1)
+            assert e == i + 1
+            assert ffi.errno == e
+        for i in range(10000):
+            ffi.errno = i
+            e = lib.f(42)
+            assert e == i + 42
+
+def test_getlasterror_working_even_with_pypys_jit():
+    if sys.platform != 'win32':
+        py.test.skip("win32-only test")
+    ffi = FFI()
+    ffi.cdef("void SetLastError(DWORD);")
+    lib = ffi.dlopen("Kernel32.dll")
+    @_run_in_multiple_threads
+    def test1():
+        for i in range(10000):
+            n = (1 << 29) + i
+            lib.SetLastError(n)
+            assert ffi.getwinerror()[0] == n


More information about the pypy-commit mailing list