Author: Armin Rigo <[email protected]>
Branch: stm-thread-2
Changeset: r61317:8eedaf9d0459
Date: 2013-02-16 11:17 +0100
http://bitbucket.org/pypy/pypy/changeset/8eedaf9d0459/

Log:    hg merge default

diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -19,7 +19,7 @@
 .. branch: numpypy-longdouble
 Long double support for numpypy
 .. branch: numpypy-real-as-view
-Convert real, imag from ufuncs to views. This involves the beginning of 
+Convert real, imag from ufuncs to views. This involves the beginning of
 view() functionality
 
 .. branch: signatures
@@ -57,7 +57,11 @@
 
 .. branch: cleanup-tests
 Consolidated the lib_pypy/pypy_test and pypy/module/test_lib_pypy tests into
-+one directory for reduced confusion and so they all run nightly.
+one directory for reduced confusion and so they all run nightly.
 
 .. branch: unquote-faster
 .. branch: urlparse-unquote-faster
+
+.. branch: signal-and-thread
+Add "__pypy__.thread.signals_enabled", a context manager. Can be used in a
+non-main thread to enable the processing of signal handlers in that thread.
diff --git a/pypy/module/__pypy__/test/test_signal.py 
b/pypy/module/__pypy__/test/test_signal.py
--- a/pypy/module/__pypy__/test/test_signal.py
+++ b/pypy/module/__pypy__/test/test_signal.py
@@ -1,5 +1,19 @@
 import sys
 
+from pypy.module.thread.test.support import GenericTestThread
+
+
+class TestThreadSignal:
+    spaceconfig = dict(usemodules=['__pypy__', 'thread'])
+
+    def test_exit_twice(self, space):
+        from pypy.module.__pypy__.interp_signal import signals_exit, 
signals_enter
+        signals_exit(space)
+        try:
+            raises(KeyError, signals_exit, space)
+        finally:
+            signals_enter(space)
+
 
 class AppTestMinimal:
     spaceconfig = dict(usemodules=['__pypy__'])
@@ -11,7 +25,76 @@
         # assert did not crash
 
 
-class AppTestThreadSignal:
+class AppTestThreadSignal(GenericTestThread):
+    spaceconfig = dict(usemodules=['__pypy__', 'thread', 'signal', 'time'])
+
+    def test_enable_signals(self):
+        import __pypy__, thread, signal, time
+
+        def subthread():
+            try:
+                with __pypy__.thread.signals_enabled:
+                    thread.interrupt_main()
+                    for i in range(10):
+                        print 'x'
+                        time.sleep(0.1)
+            except BaseException, e:
+                interrupted.append(e)
+            finally:
+                done.append(None)
+
+        # This is normally called by app_main.py
+        signal.signal(signal.SIGINT, signal.default_int_handler)
+
+        for i in range(10):
+            __pypy__.thread._signals_exit()
+            try:
+                done = []
+                interrupted = []
+                thread.start_new_thread(subthread, ())
+                for i in range(10):
+                    if len(done): break
+                    print '.'
+                    time.sleep(0.1)
+                assert len(done) == 1
+                assert len(interrupted) == 1
+                assert 'KeyboardInterrupt' in interrupted[0].__class__.__name__
+            finally:
+                __pypy__.thread._signals_enter()
+
+    def test_thread_fork_signals(self):
+        import __pypy__
+        import os, thread, signal
+
+        if not hasattr(os, 'fork'):
+            skip("No fork on this platform")
+
+        def fork():
+            with __pypy__.thread.signals_enabled:
+                return os.fork()
+
+        def threadfunction():
+            pid = fork()
+            if pid == 0:
+                print 'in child'
+                # signal() only works from the 'main' thread
+                signal.signal(signal.SIGUSR1, signal.SIG_IGN)
+                os._exit(42)
+            else:
+                self.timeout_killer(pid, 5)
+                exitcode = os.waitpid(pid, 0)[1]
+                feedback.append(exitcode)
+
+        feedback = []
+        thread.start_new_thread(threadfunction, ())
+        self.waitfor(lambda: feedback)
+        # if 0, an (unraisable) exception was raised from the forked thread.
+        # if 9, process was killed by timer.
+        # if 42<<8, os._exit(42) was correctly reached.
+        assert feedback == [42<<8]
+
+
+class AppTestThreadSignalLock:
     spaceconfig = dict(usemodules=['__pypy__', 'thread', 'signal'])
 
     def setup_class(cls):
@@ -22,11 +105,11 @@
 
     def test_enable_signals(self):
         import __pypy__, thread, signal, time
-        #
+
         interrupted = []
         lock = thread.allocate_lock()
         lock.acquire()
-        #
+
         def subthread():
             try:
                 time.sleep(0.25)
@@ -34,8 +117,9 @@
                     thread.interrupt_main()
             except BaseException, e:
                 interrupted.append(e)
-            lock.release()
-        #
+            finally:
+                lock.release()
+
         thread.start_new_thread(subthread, ())
         lock.acquire()
         assert len(interrupted) == 1
diff --git a/pypy/module/_cffi_backend/newtype.py 
b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -264,8 +264,8 @@
 
 # ____________________________________________________________
 
-@unwrap_spec(name=str)
-def new_enum_type(space, name, w_enumerators, w_enumvalues):
+@unwrap_spec(name=str, basectype=ctypeobj.W_CType)
+def new_enum_type(space, name, w_enumerators, w_enumvalues, basectype):
     enumerators_w = space.fixedview(w_enumerators)
     enumvalues_w  = space.fixedview(w_enumvalues)
     if len(enumerators_w) != len(enumvalues_w):
@@ -273,53 +273,26 @@
                              space.wrap("tuple args must have the same size"))
     enumerators = [space.str_w(w) for w in enumerators_w]
     #
-    smallest_value = 0
-    largest_value = r_uint(0)
-    i = 0
+    if (not isinstance(basectype, ctypeprim.W_CTypePrimitiveSigned) and
+        not isinstance(basectype, ctypeprim.W_CTypePrimitiveUnsigned)):
+        raise OperationError(space.w_TypeError,
+              space.wrap("expected a primitive signed or unsigned base type"))
+    #
+    lvalue = lltype.malloc(rffi.CCHARP.TO, basectype.size, flavor='raw')
     try:
         for w in enumvalues_w:
-            try:
-                ulvalue = space.uint_w(w)
-            except OperationError, e:
-                if not e.match(space, space.w_ValueError):
-                    raise
-                lvalue = space.int_w(w)
-                if lvalue < smallest_value:
-                    smallest_value = lvalue
-            else:
-                if ulvalue > largest_value:
-                    largest_value = ulvalue
-            i += 1    # 'i' is here for the exception case, see below
-    except OperationError, e:
-        if not e.match(space, space.w_OverflowError):
-            raise
-        raise operationerrfmt(space.w_OverflowError,
-                              "enum '%s' declaration for '%s' does not fit "
-                              "a long or unsigned long",
-                              name, enumerators[i])
+            # detects out-of-range or badly typed values
+            basectype.convert_from_object(lvalue, w)
+    finally:
+        lltype.free(lvalue, flavor='raw')
     #
-    if smallest_value < 0:
-        if (smallest_value >= intmask(most_neg_value_of(rffi.INT)) and
-             largest_value <= r_uint(most_pos_value_of(rffi.INT))):
-            size = rffi.sizeof(rffi.INT)
-            align = alignment(rffi.INT)
-        elif largest_value <= r_uint(most_pos_value_of(rffi.LONG)):
-            size = rffi.sizeof(rffi.LONG)
-            align = alignment(rffi.LONG)
-        else:
-            raise operationerrfmt(space.w_OverflowError,
-                         "enum '%s' values don't all fit into either 'long' "
-                         "or 'unsigned long'", name)
+    size = basectype.size
+    align = basectype.align
+    if isinstance(basectype, ctypeprim.W_CTypePrimitiveSigned):
         enumvalues = [space.int_w(w) for w in enumvalues_w]
         ctype = ctypeenum.W_CTypeEnumSigned(space, name, size, align,
                                             enumerators, enumvalues)
     else:
-        if largest_value <= r_uint(most_pos_value_of(rffi.UINT)):
-            size = rffi.sizeof(rffi.UINT)
-            align = alignment(rffi.UINT)
-        else:
-            size = rffi.sizeof(rffi.ULONG)
-            align = alignment(rffi.ULONG)
         enumvalues = [space.uint_w(w) for w in enumvalues_w]
         ctype = ctypeenum.W_CTypeEnumUnsigned(space, name, size, align,
                                               enumerators, enumvalues)
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py 
b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1264,25 +1264,29 @@
     py.test.raises(TypeError, callback, BFunc, cb, -42)
 
 def test_enum_type():
-    BEnum = new_enum_type("foo", (), ())
+    BUInt = new_primitive_type("unsigned int")
+    BEnum = new_enum_type("foo", (), (), BUInt)
     assert repr(BEnum) == "<ctype 'enum foo'>"
     assert BEnum.kind == "enum"
     assert BEnum.cname == "enum foo"
     assert BEnum.elements == {}
     #
-    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+    BInt = new_primitive_type("int")
+    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
     assert BEnum.kind == "enum"
     assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
     # 'elements' is not the real dict, but merely a copy
     BEnum.elements[2] = '??'
     assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
     #
-    BEnum = new_enum_type("bar", ('ab', 'cd'), (5, 5))
+    BEnum = new_enum_type("bar", ('ab', 'cd'), (5, 5), BUInt)
     assert BEnum.elements == {5: 'ab'}
     assert BEnum.relements == {'ab': 5, 'cd': 5}
 
 def test_cast_to_enum():
-    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+    BInt = new_primitive_type("int")
+    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
+    assert sizeof(BEnum) == sizeof(BInt)
     e = cast(BEnum, 0)
     assert repr(e) == "<cdata 'enum foo' 0: def>"
     assert repr(cast(BEnum, -42)) == "<cdata 'enum foo' -42>"
@@ -1294,18 +1298,27 @@
     assert int(cast(BEnum, -242 + 2**128)) == -242
     assert string(cast(BEnum, -242 + 2**128)) == '-242'
     #
-    BEnum = new_enum_type("bar", ('def', 'c', 'ab'), (0, 1, 20))
+    BUInt = new_primitive_type("unsigned int")
+    BEnum = new_enum_type("bar", ('def', 'c', 'ab'), (0, 1, 20), BUInt)
     e = cast(BEnum, -1)
     assert repr(e) == "<cdata 'enum bar' 4294967295>"     # unsigned int
+    #
+    BLong = new_primitive_type("long")
+    BEnum = new_enum_type("baz", (), (), BLong)
+    assert sizeof(BEnum) == sizeof(BLong)
+    e = cast(BEnum, -1)
+    assert repr(e) == "<cdata 'enum baz' -1>"
 
 def test_enum_with_non_injective_mapping():
-    BEnum = new_enum_type("foo", ('ab', 'cd'), (7, 7))
+    BInt = new_primitive_type("int")
+    BEnum = new_enum_type("foo", ('ab', 'cd'), (7, 7), BInt)
     e = cast(BEnum, 7)
     assert repr(e) == "<cdata 'enum foo' 7: ab>"
     assert string(e) == 'ab'
 
 def test_enum_in_struct():
-    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+    BInt = new_primitive_type("int")
+    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
     BStruct = new_struct_type("bar")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BEnum, -1)])
@@ -1318,7 +1331,7 @@
         "unsupported operand type for int(): 'NoneType'" in str(e.value)) #PyPy
     py.test.raises(TypeError, 'p.a1 = "def"')
     if sys.version_info < (3,):
-        BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,))
+        BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,), BInt)
         assert string(cast(BEnum2, 5)) == 'abc'
         assert type(string(cast(BEnum2, 5))) is str
 
@@ -1327,66 +1340,25 @@
     max_int = max_uint // 2
     max_ulong = 2 ** (size_of_long()*8) - 1
     max_long = max_ulong // 2
-    # 'unsigned int' case
-    e = new_enum_type("foo", ('a', 'b'), (0, 3))
-    assert sizeof(e) == size_of_int()
-    assert int(cast(e, -1)) == max_uint     # 'e' is unsigned
-    e = new_enum_type("foo", ('a', 'b'), (0, max_uint))
-    assert sizeof(e) == size_of_int()
-    assert int(cast(e, -1)) == max_uint
-    assert e.elements == {0: 'a', max_uint: 'b'}
-    assert e.relements == {'a': 0, 'b': max_uint}
-    # 'signed int' case
-    e = new_enum_type("foo", ('a', 'b'), (-1, max_int))
-    assert sizeof(e) == size_of_int()
-    assert int(cast(e, -1)) == -1
-    assert e.elements == {-1: 'a', max_int: 'b'}
-    assert e.relements == {'a': -1, 'b': max_int}
-    e = new_enum_type("foo", ('a', 'b'), (-max_int-1, max_int))
-    assert sizeof(e) == size_of_int()
-    assert int(cast(e, -1)) == -1
-    assert e.elements == {-max_int-1: 'a', max_int: 'b'}
-    assert e.relements == {'a': -max_int-1, 'b': max_int}
-    # 'unsigned long' case
-    e = new_enum_type("foo", ('a', 'b'), (0, max_long))
-    assert sizeof(e) == size_of_long()
-    assert int(cast(e, -1)) == max_ulong     # 'e' is unsigned
-    e = new_enum_type("foo", ('a', 'b'), (0, max_ulong))
-    assert sizeof(e) == size_of_long()
-    assert int(cast(e, -1)) == max_ulong
-    assert e.elements == {0: 'a', max_ulong: 'b'}
-    assert e.relements == {'a': 0, 'b': max_ulong}
-    # 'signed long' case
-    e = new_enum_type("foo", ('a', 'b'), (-1, max_long))
-    assert sizeof(e) == size_of_long()
-    assert int(cast(e, -1)) == -1
-    assert e.elements == {-1: 'a', max_long: 'b'}
-    assert e.relements == {'a': -1, 'b': max_long}
-    e = new_enum_type("foo", ('a', 'b'), (-max_long-1, max_long))
-    assert sizeof(e) == size_of_long()
-    assert int(cast(e, -1)) == -1
-    assert e.elements == {-max_long-1: 'a', max_long: 'b'}
-    assert e.relements == {'a': -max_long-1, 'b': max_long}
-    # overflow: both negative items and items larger than max_long
-    e = py.test.raises(OverflowError, new_enum_type, "foo", ('a', 'b'),
-                       (-1, max_long + 1))
-    assert str(e.value) == (
-        "enum 'foo' values don't all fit into either 'long' "
-        "or 'unsigned long'")
-    # overflow: items smaller than -max_long-1
-    e = py.test.raises(OverflowError, new_enum_type, "foo", ('a', 'b'),
-                       (-max_long-2, 5))
-    assert str(e.value) == (
-        "enum 'foo' declaration for 'a' does not fit a long or unsigned long")
-    # overflow: items larger than max_ulong
-    e = py.test.raises(OverflowError, new_enum_type, "foo", ('a', 'b'),
-                       (5, max_ulong+1))
-    assert str(e.value) == (
-        "enum 'foo' declaration for 'b' does not fit a long or unsigned long")
+    for BPrimitive in [new_primitive_type("int"),
+                       new_primitive_type("unsigned int"),
+                       new_primitive_type("long"),
+                       new_primitive_type("unsigned long")]:
+        for x in [max_uint, max_int, max_ulong, max_long]:
+            for testcase in [x, x+1, -x-1, -x-2]:
+                if int(cast(BPrimitive, testcase)) == testcase:
+                    # fits
+                    BEnum = new_enum_type("foo", ("AA",), (testcase,),
+                                          BPrimitive)
+                    assert int(cast(BEnum, testcase)) == testcase
+                else:
+                    # overflows
+                    py.test.raises(OverflowError, new_enum_type,
+                                   "foo", ("AA",), (testcase,), BPrimitive)
 
 def test_callback_returning_enum():
     BInt = new_primitive_type("int")
-    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
     def cb(n):
         if n & 1:
             return cast(BEnum, n)
@@ -1402,9 +1374,9 @@
 
 def test_callback_returning_enum_unsigned():
     BInt = new_primitive_type("int")
-    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, 20))
+    BUInt = new_primitive_type("unsigned int")
+    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, 20), BUInt)
     def cb(n):
-        print n
         if n & 1:
             return cast(BEnum, n)
         else:
diff --git a/pypy/module/micronumpy/test/test_numarray.py 
b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -1,5 +1,5 @@
-
-import py, sys
+import py
+import sys
 
 from pypy.conftest import option
 from pypy.module.micronumpy.appbridge import get_appbridge_cache
@@ -7,6 +7,7 @@
 from pypy.module.micronumpy.interp_numarray import W_NDimArray
 from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
 
+
 class MockDtype(object):
     class itemtype(object):
         @staticmethod
@@ -24,9 +25,11 @@
 def create_slice(a, chunks):
     return Chunks(chunks).apply(W_NDimArray(a)).implementation
 
+
 def create_array(*args, **kwargs):
     return W_NDimArray.from_shape(*args, **kwargs).implementation
 
+
 class TestNumArrayDirect(object):
     def newslice(self, *args):
         return self.space.newslice(*[self.space.wrap(arg) for arg in args])
@@ -1202,7 +1205,7 @@
         assert d.shape == (3, 3)
         assert d.dtype == dtype('int32')
         assert (d == [[1, 0, 0], [0, 1, 0], [0, 0, 1]]).all()
-   
+
     def test_eye(self):
         from _numpypy import eye
         from _numpypy import int32, dtype
@@ -1232,9 +1235,6 @@
         assert g.shape == (3, 4)
         assert (g == [[0, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0]]).all()
 
-
-
-
     def test_prod(self):
         from _numpypy import array
         a = array(range(1, 6))
@@ -1473,6 +1473,11 @@
         assert len(a) == 6
         assert (a == [0,1,2,3,4,5]).all()
         assert a.dtype is dtype(int)
+        a = concatenate((a1, a2), axis=1)
+        assert (a == [0,1,2,3,4,5]).all()
+        a = concatenate((a1, a2), axis=-1)
+        assert (a == [0,1,2,3,4,5]).all()
+
         b1 = array([[1, 2], [3, 4]])
         b2 = array([[5, 6]])
         b = concatenate((b1, b2), axis=0)
@@ -1488,16 +1493,29 @@
         f = concatenate((f1, [2], f1, [7]))
         assert (f == [0,1,2,0,1,7]).all()
 
-        bad_axis = raises(IndexError, concatenate, (a1,a2), axis=1)
-        assert str(bad_axis.value) == "axis 1 out of bounds [0, 1)"
+        g1 = array([[0,1,2]])
+        g2 = array([[3,4,5]])
+        g = concatenate((g1, g2), axis=-2)
+        assert (g == [[0,1,2],[3,4,5]]).all()
+        exc = raises(IndexError, concatenate, (g1, g2), axis=2)
+        assert str(exc.value) == "axis 2 out of bounds [0, 2)"
+        exc = raises(IndexError, concatenate, (g1, g2), axis=-3)
+        assert str(exc.value) == "axis -3 out of bounds [0, 2)"
 
-        concat_zero = raises(ValueError, concatenate, ())
-        assert str(concat_zero.value) == \
-            "need at least one array to concatenate"
+        exc = raises(ValueError, concatenate, ())
+        assert str(exc.value) == \
+                "need at least one array to concatenate"
 
-        dims_disagree = raises(ValueError, concatenate, (a1, b1), axis=0)
-        assert str(dims_disagree.value) == \
-            "all the input arrays must have same number of dimensions"
+        exc = raises(ValueError, concatenate, (a1, b1), axis=0)
+        assert str(exc.value) == \
+                "all the input arrays must have same number of dimensions"
+
+        g1 = array([0,1,2])
+        g2 = array([[3,4,5]])
+        exc = raises(ValueError, concatenate, (g1, g2), axis=2)
+        assert str(exc.value) == \
+                "all the input arrays must have same number of dimensions"
+
         a = array([1, 2, 3, 4, 5, 6])
         a = (a + a)[::2]
         b = concatenate((a[:3], a[-3:]))
@@ -1583,7 +1601,7 @@
                                            [[3, 9], [6, 12]]])).all() 
         assert (x.swapaxes(1, 2) == array([[[1, 4], [2, 5], [3, 6]], 
                                            [[7, 10], [8, 11],[9, 12]]])).all() 
-        
+
         # test slice
         assert (x[0:1,0:2].swapaxes(0,2) == array([[[1], [4]], [[2], [5]], 
                                                    [[3], [6]]])).all()
@@ -1745,13 +1763,13 @@
         assert a[1] == 0xff
         assert len(a.data) == 16
 
-
     def test_explicit_dtype_conversion(self):
         from _numpypy import array
         a = array([1.0, 2.0])
         b = array(a, dtype='d')
         assert a.dtype is b.dtype
 
+
 class AppTestMultiDim(BaseNumpyAppTest):
     def test_init(self):
         import _numpypy
@@ -2043,6 +2061,7 @@
                             False, False, True, False, False, False]).all()
         assert ((b > range(12)) == [False, True, True,False, True, True,
                             False, False, True, False, False, False]).all()
+
     def test_flatiter_view(self):
         from _numpypy import arange
         a = arange(10).reshape(5, 2)
@@ -2263,10 +2282,10 @@
         a = arange(12).reshape(2, 3, 2)
         assert (a.diagonal(0, 0, 1) == [[0, 8], [1, 9]]).all()
         assert a.diagonal(3, 0, 1).shape == (2, 0)
-        assert (a.diagonal(1, 0, 1) == [[2, 10], [3, 11]]).all()         
-        assert (a.diagonal(0, 2, 1) == [[0, 3], [6, 9]]).all()        
-        assert (a.diagonal(2, 2, 1) == [[4], [10]]).all()        
-        assert (a.diagonal(1, 2, 1) == [[2, 5], [8, 11]]).all()        
+        assert (a.diagonal(1, 0, 1) == [[2, 10], [3, 11]]).all()
+        assert (a.diagonal(0, 2, 1) == [[0, 3], [6, 9]]).all()
+        assert (a.diagonal(2, 2, 1) == [[4], [10]]).all()
+        assert (a.diagonal(1, 2, 1) == [[2, 5], [8, 11]]).all()
 
     def test_diagonal_axis_neg_ofs(self):
         from _numpypy import arange
@@ -2274,6 +2293,7 @@
         assert (a.diagonal(-1, 0, 1) == [[6], [7]]).all()
         assert a.diagonal(-2, 0, 1).shape == (2, 0)
 
+
 class AppTestSupport(BaseNumpyAppTest):
     def setup_class(cls):
         import struct
@@ -2444,6 +2464,7 @@
         assert (a.argsort(axis=0) == [[1, 0, 0], [0, 1, 1]]).all()
         assert (a.argsort(axis=1) == [[2, 1, 0], [0, 1, 2]]).all()
 
+
 class AppTestRanges(BaseNumpyAppTest):
     def test_arange(self):
         from _numpypy import arange, dtype
@@ -2489,6 +2510,7 @@
         cache.w_array_repr = cls.old_array_repr
         cache.w_array_str = cls.old_array_str
 
+
 class AppTestRecordDtype(BaseNumpyAppTest):
     def test_zeros(self):
         from _numpypy import zeros, integer
@@ -2659,4 +2681,3 @@
         assert x.__pypy_data__ is obj
         del x.__pypy_data__
         assert x.__pypy_data__ is None
-    
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -1530,8 +1530,8 @@
 
         def byteswap(self, w_v):
             value = self.unbox(w_v)
-            result = StringBuilder(12)
-            pack_float80(result, value, not native_is_bigendian)
+            result = StringBuilder(10)
+            pack_float80(result, value, 10, not native_is_bigendian)
             return self.box(unpack_float80(result.build(), 
native_is_bigendian))
 
     NonNativeFloat96 = Float96
@@ -1560,8 +1560,8 @@
 
         def byteswap(self, w_v):
             value = self.unbox(w_v)
-            result = StringBuilder(16)
-            pack_float80(result, value, not native_is_bigendian)
+            result = StringBuilder(10)
+            pack_float80(result, value, 10, not native_is_bigendian)
             return self.box(unpack_float80(result.build(), 
native_is_bigendian))
 
     NonNativeFloat128 = Float128
diff --git a/pypy/module/signal/interp_signal.py 
b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -32,8 +32,7 @@
         p = pypysig_getaddr_occurred()
         p.c_value = value
 
-    @staticmethod
-    def rearm_ticker():
+    def rearm_ticker(self):
         p = pypysig_getaddr_occurred()
         p.c_value = -1
 
@@ -71,7 +70,7 @@
         if self.fire_in_another_thread:
             if self.space.threadlocals.signals_enabled():
                 self.fire_in_another_thread = False
-                SignalActionFlag.rearm_ticker()
+                self.space.actionflag.rearm_ticker()
                 # this occurs when we just switched to the main thread
                 # and there is a signal pending: we force the ticker to
                 # -1, which should ensure perform() is called quickly.
@@ -101,6 +100,7 @@
         if not we_are_translated():
             self.pending_signal = cpy_signal.SIGINT
             # ^^^ may override another signal, but it's just for testing
+            self.fire_in_another_thread = True
         else:
             pypysig_pushback(cpy_signal.SIGINT)
 
diff --git a/pypy/module/thread/test/test_thread.py 
b/pypy/module/thread/test/test_thread.py
--- a/pypy/module/thread/test/test_thread.py
+++ b/pypy/module/thread/test/test_thread.py
@@ -220,18 +220,18 @@
         import signal
 
         def f():
-            for x in range(50):
+            for x in range(5):
                 if waiting:
                     thread.interrupt_main()
                     return
                 print 'tock...', x  # <-force the GIL to be released, as
-                time.sleep(0.01)    #   time.sleep doesn't do non-translated
+                time.sleep(0.1)    #   time.sleep doesn't do non-translated
 
         def busy_wait():
             waiting.append(None)
-            for x in range(100):
+            for x in range(10):
                 print 'tick...', x  # <-force the GIL to be released, as
-                time.sleep(0.01)    #   time.sleep doesn't do non-translated
+                time.sleep(0.1)    #   time.sleep doesn't do non-translated
             waiting.pop()
 
         # This is normally called by app_main.py
diff --git a/pypy/module/thread/threadlocals.py 
b/pypy/module/thread/threadlocals.py
--- a/pypy/module/thread/threadlocals.py
+++ b/pypy/module/thread/threadlocals.py
@@ -17,6 +17,7 @@
     def _cleanup_(self):
         self._valuedict.clear()
         self._signalsenabled.clear()
+        self._mainthreadident = 0
         if self.can_cache:
             self._mostrecentkey = 0        # fast minicaching for the common 
case
             self._mostrecentvalue = None   # fast minicaching for the common 
case
@@ -39,12 +40,17 @@
         if value is not None:
             if len(self._valuedict) == 0:
                 self._signalsenabled[ident] = 1    # the main thread is enabled
+                self._mainthreadident = ident
             self._valuedict[ident] = value
         else:
             try:
                 del self._valuedict[ident]
             except KeyError:
                 pass
+            try:
+                del self._signalsenabled[ident]
+            except KeyError:
+                pass
         if self.can_cache:
             # update the minicache to prevent it from containing an outdated 
value
             self._mostrecentkey = ident
@@ -60,10 +66,7 @@
 
     def disable_signals(self):
         ident = rthread.get_ident()
-        try:
-            new = self._signalsenabled[ident] - 1
-        except KeyError:
-            return
+        new = self._signalsenabled[ident] - 1
         if new > 0:
             self._signalsenabled[ident] = new
         else:
@@ -88,7 +91,8 @@
         # figure out a non-hackish way to handle thread+signal+fork :-(
         ident = rthread.get_ident()
         old = self._signalsenabled.get(ident, 0)
+        if ident is not self._mainthreadident:
+            self._mainthreadident = ident
+            old += 1
         self._signalsenabled.clear()
-        if old == 0:
-            old = 1
         self._signalsenabled[ident] = old
diff --git a/rpython/rlib/rstruct/ieee.py b/rpython/rlib/rstruct/ieee.py
--- a/rpython/rlib/rstruct/ieee.py
+++ b/rpython/rlib/rstruct/ieee.py
@@ -25,26 +25,23 @@
     return int_part
 
 def float_unpack(Q, size):
-    """Convert a 16-bit, 32-bit 64-bit integer created
+    """Convert a 16-bit, 32-bit, or 64-bit integer created
     by float_pack into a Python float."""
     if size == 8:
         MIN_EXP = -1021  # = sys.float_info.min_exp
         MAX_EXP = 1024   # = sys.float_info.max_exp
         MANT_DIG = 53    # = sys.float_info.mant_dig
         BITS = 64
-        one = r_ulonglong(1)
     elif size == 4:
         MIN_EXP = -125   # C's FLT_MIN_EXP
         MAX_EXP = 128    # FLT_MAX_EXP
         MANT_DIG = 24    # FLT_MANT_DIG
         BITS = 32
-        one = r_ulonglong(1)
     elif size == 2:
         MIN_EXP = -13
         MAX_EXP = 16
         MANT_DIG = 11
         BITS = 16
-        one = r_ulonglong(1)
     else:
         raise ValueError("invalid size value")
 
@@ -56,6 +53,7 @@
             raise ValueError("input '%r' out of range '%r'" % (Q, Q>>BITS))
 
     # extract pieces with assumed 1.mant values
+    one = r_ulonglong(1)
     sign = rarithmetic.intmask(Q >> BITS - 1)
     exp = rarithmetic.intmask((Q & ((one << BITS - 1) - (one << MANT_DIG - 
1))) >> MANT_DIG - 1)
     mant = Q & ((one << MANT_DIG - 1) - 1)
@@ -72,27 +70,32 @@
         result = math.ldexp(mant, exp + MIN_EXP - MANT_DIG - 1)
     return -result if sign else result
 
-def float_unpack80(QQ):
+def float_unpack80(QQ, size):
     '''Unpack a (mant, exp) tuple of r_ulonglong in 80-bit extended format
     into a long double float
     '''
-    MIN_EXP = -16381
-    MAX_EXP = 16384
-    MANT_DIG = 64
-    TOPBITS = 80 - 64
-    one = r_ulonglong(1)
+    if size == 10 or size == 12 or size == 16:
+        MIN_EXP = -16381
+        MAX_EXP = 16384
+        MANT_DIG = 64
+        TOP_BITS = 80 - 64
+    else:
+        raise ValueError("invalid size value")
+
     if len(QQ) != 2:
         raise ValueError("QQ must be two 64 bit uints")
+
     if not objectmodel.we_are_translated():
         # This tests generates wrong code when translated:
         # with gcc, shifting a 64bit int by 64 bits does
         # not change the value.
-        if QQ[1] >> TOPBITS:
-            raise ValueError("input '%r' out of range '%r'" % (QQ, 
QQ[1]>>TOPBITS))
+        if QQ[1] >> TOP_BITS:
+            raise ValueError("input '%r' out of range '%r'" % (QQ, 
QQ[1]>>TOP_BITS))
 
     # extract pieces with explicit one in MANT_DIG
-    sign = rarithmetic.intmask(QQ[1] >> TOPBITS - 1)
-    exp = rarithmetic.intmask((QQ[1] & ((one << TOPBITS - 1) - 1)))
+    one = r_ulonglong(1)
+    sign = rarithmetic.intmask(QQ[1] >> TOP_BITS - 1)
+    exp = rarithmetic.intmask((QQ[1] & ((one << TOP_BITS - 1) - 1)))
     mant = QQ[0]
 
     if exp == MAX_EXP - MIN_EXP + 2:
@@ -171,14 +174,18 @@
     sign = r_ulonglong(sign)
     return ((sign << BITS - 1) | (exp << MANT_DIG - 1)) | mant
 
-def float_pack80(x):
+def float_pack80(x, size):
     """Convert a Python float or longfloat x into two 64-bit unsigned integers
     with 80 bit extended representation."""
-    MIN_EXP = -16381
-    MAX_EXP = 16384
-    MANT_DIG = 64
-    BITS = 80
     x = float(x) # longfloat not really supported
+    if size == 10 or size == 12 or size == 16:
+        MIN_EXP = -16381
+        MAX_EXP = 16384
+        MANT_DIG = 64
+        BITS = 80
+    else:
+        raise ValueError("invalid size value")
+
     sign = rfloat.copysign(1.0, x) < 0.0
     if not rfloat.isfinite(x):
         if rfloat.isinf(x):
@@ -235,32 +242,32 @@
     result.append("".join(l))
 
 @jit.unroll_safe
-def pack_float80(result, x, be):
+def pack_float80(result, x, size, be):
     l = []
-    unsigned = float_pack80(x)
+    unsigned = float_pack80(x, size)
     for i in range(8):
         l.append(chr((unsigned[0] >> (i * 8)) & 0xFF))
     for i in range(2):
         l.append(chr((unsigned[1] >> (i * 8)) & 0xFF))
+    for i in range(size - 10):
+        l.append('\x00')
     if be:
         l.reverse()
     result.append("".join(l))
 
 def unpack_float(s, be):
     unsigned = r_ulonglong(0)
-    for i in range(len(s)):
-        c = ord(s[len(s) - 1 - i if be else i])
+    for i in range(min(len(s), 8)):
+        c = ord(s[-i - 1 if be else i])
         unsigned |= r_ulonglong(c) << (i * 8)
     return float_unpack(unsigned, len(s))
 
 def unpack_float80(s, be):
-    if len(s) != 10:
-        raise ValueError
     QQ = [r_ulonglong(0), r_ulonglong(0)]
     for i in range(8):
-        c = ord(s[9 - i if be else i])
+        c = ord(s[-i - 1 if be else i])
         QQ[0] |= r_ulonglong(c) << (i * 8)
     for i in range(8, 10):
-        c = ord(s[9 - i if be else i])
+        c = ord(s[-i - 1 if be else i])
         QQ[1] |= r_ulonglong(c) << ((i - 8) * 8)
-    return float_unpack80(QQ)
+    return float_unpack80(QQ, len(s))
diff --git a/rpython/rlib/rstruct/test/test_ieee.py 
b/rpython/rlib/rstruct/test/test_ieee.py
--- a/rpython/rlib/rstruct/test/test_ieee.py
+++ b/rpython/rlib/rstruct/test/test_ieee.py
@@ -8,6 +8,55 @@
 from rpython.translator.c.test.test_genc import compile
 
 
+class TestFloatSpecific:
+    def test_halffloat_exact(self):
+        #testcases generated from numpy.float16(x).view('uint16')
+        cases = [[0, 0], [10, 18688], [-10, 51456], [10e3, 28898],
+                 [float('inf'), 31744], [-float('inf'), 64512]]
+        for c, h in cases:
+            hbit = ieee.float_pack(c, 2)
+            assert hbit == h
+            assert c == ieee.float_unpack(h, 2)
+
+    def test_halffloat_inexact(self):
+        #testcases generated from numpy.float16(x).view('uint16')
+        cases = [[10.001, 18688, 10.], [-10.001, 51456, -10],
+                 [0.027588, 10000, 0.027587890625],
+                 [22001, 30047, 22000]]
+        for c, h, f in cases:
+            hbit = ieee.float_pack(c, 2)
+            assert hbit == h
+            assert f == ieee.float_unpack(h, 2)
+
+    def test_halffloat_overunderflow(self):
+        import math
+        cases = [[670000, float('inf')], [-67000, -float('inf')],
+                 [1e-08, 0], [-1e-8, -0.]]
+        for f1, f2 in cases:
+            try:
+                f_out = ieee.float_unpack(ieee.float_pack(f1, 2), 2)
+            except OverflowError:
+                f_out = math.copysign(float('inf'), f1)
+            assert f_out == f2
+            assert math.copysign(1., f_out) == math.copysign(1., f2)
+
+    def test_float80_exact(self):
+        s = []
+        ieee.pack_float80(s, -1., 16, False)
+        assert repr(s[-1]) == 
repr('\x00\x00\x00\x00\x00\x00\x00\x80\xff\xbf\x00\x00\x00\x00\x00\x00')
+        ieee.pack_float80(s, -1., 16, True)
+        assert repr(s[-1]) == 
repr('\x00\x00\x00\x00\x00\x00\xbf\xff\x80\x00\x00\x00\x00\x00\x00\x00')
+        ieee.pack_float80(s, -123.456, 16, False)
+        assert repr(s[-1]) == 
repr('\x00\xb8\xf3\xfd\xd4x\xe9\xf6\x05\xc0\x00\x00\x00\x00\x00\x00')
+        ieee.pack_float80(s, -123.456, 16, True)
+        assert repr(s[-1]) == 
repr('\x00\x00\x00\x00\x00\x00\xc0\x05\xf6\xe9x\xd4\xfd\xf3\xb8\x00')
+
+        x = 
ieee.unpack_float80('\x00\x00\x00\x00\x00\x00\x00\x80\xff?\xc8\x01\x00\x00\x00\x00',
 False)
+        assert x == 1.0
+        x = 
ieee.unpack_float80('\x00\x00\x7f\x83\xe1\x91?\xff\x80\x00\x00\x00\x00\x00\x00\x00',
 True)
+        assert x == 1.0
+
+
 class TestFloatPacking:
     def setup_class(cls):
         if sys.version_info < (2, 6):
@@ -15,25 +64,20 @@
 
     def check_float(self, x):
         # check roundtrip
-        Q = ieee.float_pack(x, 8)
-        y = ieee.float_unpack(Q, 8)
-        assert repr(x) == repr(y), '%r != %r, Q=%r' % (x, y, Q)
+        for size in [10, 12, 16]:
+            for be in [False, True]:
+                Q = []
+                ieee.pack_float80(Q, x, size, be)
+                Q = Q[0]
+                y = ieee.unpack_float80(Q, be)
+                assert repr(x) == repr(y), '%r != %r, Q=%r' % (x, y, Q)
 
-        Q = ieee.float_pack80(x)
-        y = ieee.float_unpack80(Q)
-        assert repr(x) == repr(y), '%r != %r, Q=%r' % (x, y, Q)
-
-        Q = []
-        ieee.pack_float(Q, x, 8, False)
-        Q = Q[0]
-        y = ieee.unpack_float(Q, False)
-        assert repr(x) == repr(y), '%r != %r, Q=%r' % (x, y, Q)
-
-        Q = []
-        ieee.pack_float80(Q, x, False)
-        Q = Q[0]
-        y = ieee.unpack_float80(Q, False)
-        assert repr(x) == repr(y), '%r != %r, Q=%r' % (x, y, Q)
+        for be in [False, True]:
+            Q = []
+            ieee.pack_float(Q, x, 8, be)
+            Q = Q[0]
+            y = ieee.unpack_float(Q, be)
+            assert repr(x) == repr(y), '%r != %r, Q=%r' % (x, y, Q)
 
         # check that packing agrees with the struct module
         struct_pack8 = struct.unpack('<Q', struct.pack('<d', x))[0]
@@ -74,26 +118,8 @@
         self.check_float(0.0)
         self.check_float(-0.0)
 
-    def test_check_size(self):
-        # these were refactored into separate pack80/unpack80 functions
-        py.test.raises(ValueError, ieee.float_pack, 1.0, 12)
-        py.test.raises(ValueError, ieee.float_pack, 1.0, 16)
-        py.test.raises(ValueError, ieee.float_unpack, 1, 12)
-        py.test.raises(ValueError, ieee.float_unpack, 1, 16)
-
     def test_nans(self):
-        Q = ieee.float_pack80(float('nan'))
-        y = ieee.float_unpack80(Q)
-        assert repr(y) == 'nan'
-        Q = ieee.float_pack(float('nan'), 8)
-        y = ieee.float_unpack(Q, 8)
-        assert repr(y) == 'nan'
-        L = ieee.float_pack(float('nan'), 4)
-        z = ieee.float_unpack(L, 4)
-        assert repr(z) == 'nan'
-        L = ieee.float_pack(float('nan'), 2)
-        z = ieee.float_unpack(L, 2)
-        assert repr(z) == 'nan'
+        self.check_float(float('nan'))
 
     def test_simple(self):
         test_values = [1e-10, 0.00123, 0.5, 0.7, 1.0, 123.456, 1e10]
@@ -142,7 +168,7 @@
 
     def test_random(self):
         # construct a Python float from random integer, using struct
-        for _ in xrange(100000):
+        for _ in xrange(10000):
             Q = random.randrange(2**64)
             x = struct.unpack('<d', struct.pack('<Q', Q))[0]
             # nans are tricky:  we can't hope to reproduce the bit
@@ -151,37 +177,6 @@
                 continue
             self.check_float(x)
 
-    def test_halffloat_exact(self):
-        #testcases generated from numpy.float16(x).view('uint16')
-        cases = [[0, 0], [10, 18688], [-10, 51456], [10e3, 28898],
-                 [float('inf'), 31744], [-float('inf'), 64512]]
-        for c, h in cases:
-            hbit = ieee.float_pack(c, 2)
-            assert hbit == h
-            assert c == ieee.float_unpack(h, 2)
-
-    def test_halffloat_inexact(self):
-        #testcases generated from numpy.float16(x).view('uint16')
-        cases = [[10.001, 18688, 10.], [-10.001, 51456, -10],
-                 [0.027588, 10000, 0.027587890625],
-                 [22001, 30047, 22000]]
-        for c, h, f in cases:
-            hbit = ieee.float_pack(c, 2)
-            assert hbit == h
-            assert f == ieee.float_unpack(h, 2)
-
-    def test_halffloat_overunderflow(self):
-        import math
-        cases = [[670000, float('inf')], [-67000, -float('inf')],
-                 [1e-08, 0], [-1e-8, -0.]]
-        for f1, f2 in cases:
-            try:
-                f_out = ieee.float_unpack(ieee.float_pack(f1, 2), 2)
-            except OverflowError:
-                f_out = math.copysign(float('inf'), f1)
-            assert f_out == f2
-            assert math.copysign(1., f_out) == math.copysign(1., f2)
-
 
 class TestCompiled:
     def test_pack_float(self):
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to