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