Author: Philip Jenvey <pjen...@underboss.org> Branch: py3k Changeset: r61291:6f8795612ffd Date: 2013-02-15 16:20 -0800 http://bitbucket.org/pypy/pypy/changeset/6f8795612ffd/
Log: merge default diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -17,8 +17,14 @@ def setvalue(self, value): self._value = value - def ismainthread(self): + def signals_enabled(self): return True + def enable_signals(self): + pass + + def disable_signals(self): + pass + def getallvalues(self): return {0: self._value} diff --git a/pypy/interpreter/test2/test_app_main.py b/pypy/interpreter/test2/test_app_main.py --- a/pypy/interpreter/test2/test_app_main.py +++ b/pypy/interpreter/test2/test_app_main.py @@ -225,11 +225,6 @@ These tests require pexpect (UNIX-only). http://pexpect.sourceforge.net/ """ - def setup_class(cls): - # some tests need to be able to import test2, change the cwd - goal_dir = os.path.abspath(os.path.join(os.path.realpath(os.path.dirname(__file__)), '..')) - os.chdir(goal_dir) - def _spawn(self, *args, **kwds): try: import pexpect @@ -484,13 +479,14 @@ child = self.spawn(['-c', 'import sys; print(sys.stdin.mode)']) child.expect('r') - def test_options_i_m(self): + def test_options_i_m(self, monkeypatch): if sys.platform == "win32": skip("close_fds is not supported on Windows platforms") if not hasattr(runpy, '_run_module_as_main'): skip("requires CPython >= 2.6") p = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'mymodule.py') p = os.path.abspath(p) + monkeypatch.chdir(os.path.dirname(app_main)) child = self.spawn(['-i', '-m', 'test2.mymodule', 'extra']) @@ -590,12 +586,13 @@ child.sendline('Not at all. They could be carried.') child.expect('A five ounce bird could not carry a one pound coconut.') - def test_no_space_before_argument(self): + def test_no_space_before_argument(self, monkeypatch): if not hasattr(runpy, '_run_module_as_main'): skip("requires CPython >= 2.6") child = self.spawn(['-cprint("hel" + "lo")']) child.expect('hello') + monkeypatch.chdir(os.path.dirname(app_main)) child = self.spawn(['-mtest2.mymodule']) child.expect('mymodule running') @@ -696,11 +693,12 @@ '-c "import sys; print(sys.warnoptions)"') assert "['ignore', 'default', 'once', 'error']" in data - def test_option_m(self): + def test_option_m(self, monkeypatch): if not hasattr(runpy, '_run_module_as_main'): skip("requires CPython >= 2.6") p = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'mymodule.py') p = os.path.abspath(p) + monkeypatch.chdir(os.path.dirname(app_main)) data = self.run('-m test2.mymodule extra') assert 'mymodule running' in data assert 'Name: __main__' in data diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -26,6 +26,16 @@ interpleveldefs[name] = "space.wrap(interp_time.%s)" % name +class ThreadModule(MixedModule): + appleveldefs = { + 'signals_enabled': 'app_signal.signals_enabled', + } + interpleveldefs = { + '_signals_enter': 'interp_signal.signals_enter', + '_signals_exit': 'interp_signal.signals_exit', + } + + class Module(MixedModule): appleveldefs = { } @@ -54,6 +64,7 @@ submodules = { "builders": BuildersModule, "time": TimeModule, + "thread": ThreadModule, } def setup_after_space_initialization(self): diff --git a/pypy/module/__pypy__/app_signal.py b/pypy/module/__pypy__/app_signal.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/app_signal.py @@ -0,0 +1,14 @@ +import __pypy__.thread + +class SignalsEnabled(object): + '''A context manager to use in non-main threads: +enables receiving signals in a "with" statement. More precisely, if a +signal is received by the process, then the signal handler might be +called either in the main thread (as usual) or within another thread +that is within a "with signals_enabled:". This other thread should be +ready to handle unexpected exceptions that the signal handler might +raise --- notably KeyboardInterrupt.''' + __enter__ = __pypy__.thread._signals_enter + __exit__ = __pypy__.thread._signals_exit + +signals_enabled = SignalsEnabled() diff --git a/pypy/module/__pypy__/interp_signal.py b/pypy/module/__pypy__/interp_signal.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_signal.py @@ -0,0 +1,6 @@ + +def signals_enter(space): + space.threadlocals.enable_signals() + +def signals_exit(space, w_ignored1=None, w_ignored2=None, w_ignored3=None): + space.threadlocals.disable_signals() diff --git a/pypy/module/__pypy__/test/test_signal.py b/pypy/module/__pypy__/test/test_signal.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_signal.py @@ -0,0 +1,81 @@ +import sys + + +class AppTestMinimal: + spaceconfig = dict(usemodules=['__pypy__']) + + def test_signal(self): + from __pypy__ import thread + with thread.signals_enabled: + pass + # assert did not crash + + +class AppTestThreadSignal: + 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() + + +class AppTestThreadSignalLock: + spaceconfig = dict(usemodules=['__pypy__', 'thread', 'signal']) + + def setup_class(cls): + if (not cls.runappdirect or + '__pypy__' not in sys.builtin_module_names): + import py + py.test.skip("this is only a test for -A runs on top of pypy") + + def test_enable_signals(self): + import __pypy__, thread, signal, time + + interrupted = [] + lock = thread.allocate_lock() + lock.acquire() + + def subthread(): + try: + time.sleep(0.25) + with __pypy__.thread.signals_enabled: + thread.interrupt_main() + except BaseException, e: + interrupted.append(e) + finally: + lock.release() + + thread.start_new_thread(subthread, ()) + lock.acquire() + assert len(interrupted) == 1 + assert 'KeyboardInterrupt' in interrupted[0].__class__.__name__ 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 @@ -1404,7 +1404,6 @@ BInt = new_primitive_type("int") BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, 20)) def cb(n): - print n if n & 1: return cast(BEnum, n) else: diff --git a/pypy/module/gc/test/test_ztranslation.py b/pypy/module/gc/test/test_ztranslation.py new file mode 100644 --- /dev/null +++ b/pypy/module/gc/test/test_ztranslation.py @@ -0,0 +1,4 @@ +from pypy.objspace.fake.checkmodule import checkmodule + +def test_checkmodule(): + checkmodule('gc') diff --git a/pypy/module/micronumpy/test/test_module.py b/pypy/module/micronumpy/test/test_module.py --- a/pypy/module/micronumpy/test/test_module.py +++ b/pypy/module/micronumpy/test/test_module.py @@ -13,11 +13,13 @@ assert sum(array(range(10))) == 45 def test_min(self): - from _numpypy import array, min + from _numpypy import array, min, zeros assert min(range(10)) == 0 assert min(array(range(10))) == 0 + assert list(min(zeros((0, 2)), axis=1)) == [] def test_max(self): - from _numpypy import array, max + from _numpypy import array, max, zeros assert max(range(10)) == 9 assert max(array(range(10))) == 9 + assert list(max(zeros((0, 2)), axis=1)) == [] 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 @@ -1662,13 +1662,13 @@ b = array([0, 1, 2], dtype=complex).astype(bool) assert (b == [False, True, True]).all() assert b.dtype == 'bool' - + a = arange(6, dtype='f4').reshape(2,3) b = a.astype('i4') a = array('x').astype('S3').dtype assert a.itemsize == 3 - + def test_base(self): from _numpypy import array assert array(1).base is None @@ -1679,6 +1679,11 @@ def test_byteswap(self): from _numpypy import array + + s1 = array(1.).byteswap().tostring() + s2 = array([1.]).byteswap().tostring() + assert s1 == s2 + a = array([1, 256 + 2, 3], dtype='i2') assert (a.byteswap() == [0x0100, 0x0201, 0x0300]).all() assert (a == [1, 256 + 2, 3]).all() @@ -1686,39 +1691,40 @@ assert (a == [0x0100, 0x0201, 0x0300]).all() a = array([1, -1, 1e300], dtype=float) - s1 = map(ord,a.tostring()) + s1 = map(ord, a.tostring()) s2 = map(ord, a.byteswap().tostring()) - assert s1[7::-1] == s2[:8] - assert s1[15:7:-1] == s2[8:16] - assert s1[:15:-1] == s2[16:] + assert a.dtype.itemsize == 8 + for i in range(a.size): + i1 = i * a.dtype.itemsize + i2 = (i+1) * a.dtype.itemsize + assert list(reversed(s1[i1:i2])) == s2[i1:i2] a = array([1+1e30j, -1, 1e10], dtype=complex) - s1 = map(ord,a.tostring()) + s1 = map(ord, a.tostring()) s2 = map(ord, a.byteswap().tostring()) - assert s1[7::-1] == s2[:8] - assert s1[15:7:-1] == s2[8:16] - assert s1[23:15:-1] == s2[16:24] - assert s1[31:23:-1] == s2[24:32] - assert s1[39:31:-1] == s2[32:40] - assert s1[:39:-1] == s2[40:] + assert a.dtype.itemsize == 16 + for i in range(a.size*2): + i1 = i * a.dtype.itemsize/2 + i2 = (i+1) * a.dtype.itemsize/2 + assert list(reversed(s1[i1:i2])) == s2[i1:i2] a = array([3.14, -1.5, 10000], dtype='float16') - s1 = map(ord,a.tostring()) + s1 = map(ord, a.tostring()) s2 = map(ord, a.byteswap().tostring()) - s3 = [s1[1], s1[0],s1[3], s1[2], s1[5], s1[4]] - assert s3 == s2 + assert a.dtype.itemsize == 2 + for i in range(a.size): + i1 = i * a.dtype.itemsize + i2 = (i+1) * a.dtype.itemsize + assert list(reversed(s1[i1:i2])) == s2[i1:i2] a = array([1, -1, 10000], dtype='longfloat') - s1 = map(ord,a.tostring()) - s2 = map(ord, a.byteswap().tostring()) - n = a.dtype.itemsize - assert s1[n-1] == s2[0] - - a = array(0., dtype='longfloat') s1 = map(ord, a.tostring()) s2 = map(ord, a.byteswap().tostring()) - n = a.dtype.itemsize - assert s1[n-1] == s2[0] + assert a.dtype.itemsize >= 8 + for i in range(a.size): + i1 = i * a.dtype.itemsize + i2 = (i+1) * a.dtype.itemsize + assert list(reversed(s1[i1:i2])) == s2[i1:i2] def test_clip(self): from _numpypy import array 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 @@ -14,8 +14,8 @@ from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rlib.rstruct.runpack import runpack from rpython.rlib.rstruct.nativefmttable import native_is_bigendian -from rpython.rlib.rstruct.ieee import (float_pack, float_unpack, pack_float80, - unpack_float, unpack_float128) +from rpython.rlib.rstruct.ieee import (float_pack, float_unpack, unpack_float, + pack_float80, unpack_float80) from rpython.tool.sourcetools import func_with_new_name from rpython.rlib import jit from rpython.rlib.rstring import StringBuilder @@ -958,7 +958,6 @@ swapped_value = byteswap(rffi.cast(self.T, value)) raw_storage_setitem(storage, i + offset, swapped_value) - class Float32(BaseType, Float): _attrs_ = () @@ -1505,7 +1504,6 @@ BoxType = interp_boxes.W_Complex64Box ComponentBoxType = interp_boxes.W_Float32Box - NonNativeComplex64 = Complex64 class Complex128(ComplexFloating, BaseType): @@ -1515,7 +1513,6 @@ BoxType = interp_boxes.W_Complex128Box ComponentBoxType = interp_boxes.W_Float64Box - NonNativeComplex128 = Complex128 if interp_boxes.long_double_size == 12: @@ -1528,17 +1525,16 @@ def runpack_str(self, s): assert len(s) == 12 - fval = unpack_float128(s, native_is_bigendian) + fval = unpack_float80(s, native_is_bigendian) return self.box(fval) def byteswap(self, w_v): value = self.unbox(w_v) result = StringBuilder(12) - pack_float80(result, value, 12, not native_is_bigendian) - return self.box(unpack_float128(result.build(), native_is_bigendian)) + pack_float80(result, value, not native_is_bigendian) + return self.box(unpack_float80(result.build(), native_is_bigendian)) - class NonNativeFloat96(Float96): - pass + NonNativeFloat96 = Float96 class Complex192(ComplexFloating, BaseType): _attrs_ = () @@ -1549,7 +1545,6 @@ NonNativeComplex192 = Complex192 - elif interp_boxes.long_double_size == 16: class Float128(BaseType, Float): _attrs_ = () @@ -1560,14 +1555,14 @@ def runpack_str(self, s): assert len(s) == 16 - fval = unpack_float128(s, native_is_bigendian) + fval = unpack_float80(s, native_is_bigendian) return self.box(fval) def byteswap(self, w_v): value = self.unbox(w_v) result = StringBuilder(16) - pack_float80(result, value, 16, not native_is_bigendian) - return self.box(unpack_float128(result.build(), native_is_bigendian)) + pack_float80(result, value, not native_is_bigendian) + return self.box(unpack_float80(result.build(), native_is_bigendian)) NonNativeFloat128 = Float128 @@ -1578,7 +1573,6 @@ BoxType = interp_boxes.W_Complex256Box ComponentBoxType = interp_boxes.W_Float128Box - NonNativeComplex256 = Complex256 class BaseStringType(object): 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 @@ -61,16 +61,16 @@ "NOT_RPYTHON" AsyncAction.__init__(self, space) self.pending_signal = -1 - self.fire_in_main_thread = False + self.fire_in_another_thread = False if self.space.config.objspace.usemodules.thread: from pypy.module.thread import gil gil.after_thread_switch = self._after_thread_switch @rgc.no_collect def _after_thread_switch(self): - if self.fire_in_main_thread: - if self.space.threadlocals.ismainthread(): - self.fire_in_main_thread = False + if self.fire_in_another_thread: + if self.space.threadlocals.signals_enabled(): + self.fire_in_another_thread = False SignalActionFlag.rearm_ticker() # this occurs when we just switched to the main thread # and there is a signal pending: we force the ticker to @@ -82,11 +82,7 @@ n = self.pending_signal if n < 0: n = pypysig_poll() while n >= 0: - if self.space.config.objspace.usemodules.thread: - in_main = self.space.threadlocals.ismainthread() - else: - in_main = True - if in_main: + if self.space.threadlocals.signals_enabled(): # If we are in the main thread, report the signal now, # and poll more self.pending_signal = -1 @@ -97,7 +93,7 @@ # Otherwise, arrange for perform() to be called again # after we switch to the main thread. self.pending_signal = n - self.fire_in_main_thread = True + self.fire_in_another_thread = True break def set_interrupt(self): @@ -105,9 +101,9 @@ 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) - self.fire_in_main_thread = True # ____________________________________________________________ @@ -204,9 +200,10 @@ if WIN32 and signum not in signal_values: raise OperationError(space.w_ValueError, space.wrap("invalid signal value")) - if not space.threadlocals.ismainthread(): + if not space.threadlocals.signals_enabled(): raise OperationError(space.w_ValueError, - space.wrap("signal only works in main thread")) + space.wrap("signal only works in main thread " + "or with __pypy__.thread.enable_signals()")) check_signum_in_range(space, signum) if space.eq_w(w_handler, space.wrap(SIG_DFL)): @@ -235,10 +232,11 @@ The fd must be non-blocking. """ - if not space.threadlocals.ismainthread(): + if not space.threadlocals.signals_enabled(): raise OperationError( space.w_ValueError, - space.wrap("set_wakeup_fd only works in main thread")) + space.wrap("set_wakeup_fd only works in main thread " + "or with __pypy__.thread.enable_signals()")) old_fd = pypysig_set_wakeup_fd(fd) return space.wrap(intmask(old_fd)) diff --git a/pypy/module/sys/initpath.py b/pypy/module/sys/initpath.py --- a/pypy/module/sys/initpath.py +++ b/pypy/module/sys/initpath.py @@ -67,6 +67,8 @@ stdlib. If it cannot be found, return (None, None). """ + if executable == '': + return None, None search = executable while True: dirname = resolvedirof(search) diff --git a/pypy/module/sys/test/test_initpath.py b/pypy/module/sys/test/test_initpath.py --- a/pypy/module/sys/test/test_initpath.py +++ b/pypy/module/sys/test/test_initpath.py @@ -10,12 +10,15 @@ b = prefix.join('lib-python', dirname).ensure(dir=1) return a, b -def test_find_stdlib(tmpdir): +def test_find_stdlib(tmpdir, monkeypatch): bin_dir = tmpdir.join('bin').ensure(dir=True) pypy = bin_dir.join('pypy').ensure(file=True) build_hierarchy(tmpdir) path, prefix = find_stdlib(None, str(pypy)) assert prefix == tmpdir + # shouldn't find stdlib if executable == '' even if parent dir has a stdlib + monkeypatch.chdir(tmpdir.join('bin')) + assert find_stdlib(None, '') == (None, None) @py.test.mark.skipif('not hasattr(os, "symlink")') def test_find_stdlib_follow_symlink(tmpdir): @@ -84,6 +87,7 @@ assert find_executable('pypy') == a.join('pypy.exe') def test_resolvedirof(tmpdir): + assert resolvedirof('') == os.path.abspath(os.path.join(os.getcwd(), '..')) foo = tmpdir.join('foo').ensure(dir=True) bar = tmpdir.join('bar').ensure(dir=True) myfile = foo.join('myfile').ensure(file=True) diff --git a/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py b/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py --- a/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py +++ b/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py @@ -132,7 +132,7 @@ assert reshape(a, (1, -1)).shape == (1, 105) assert reshape(a, (1, 1, -1)).shape == (1, 1, 105) assert reshape(a, (-1, 1, 1)).shape == (105, 1, 1) - + def test_transpose(self): from numpypy import arange, array, transpose, ones x = arange(4).reshape((2,2)) @@ -141,7 +141,7 @@ raises(NotImplementedError, "transpose(x, axes=(1, 0, 2))") # x = ones((1, 2, 3)) # assert transpose(x, (1, 0, 2)).shape == (2, 1, 3) - + def test_fromnumeric(self): from numpypy import array, swapaxes x = array([[1,2,3]]) diff --git a/pypy/module/test_lib_pypy/numpypy/test_numpy.py b/pypy/module/test_lib_pypy/numpypy/test_numpy.py --- a/pypy/module/test_lib_pypy/numpypy/test_numpy.py +++ b/pypy/module/test_lib_pypy/numpypy/test_numpy.py @@ -12,3 +12,11 @@ pass import numpypy import numpy # works after 'numpypy' has been imported + + def test_min_max_after_import(self): + from numpypy import * + assert min(1, 100) == 1 + assert min(100, 1) == 1 + + assert max(1, 100) == 100 + assert max(100, 1) == 100 diff --git a/pypy/module/thread/gil.py b/pypy/module/thread/gil.py --- a/pypy/module/thread/gil.py +++ b/pypy/module/thread/gil.py @@ -7,7 +7,7 @@ # all but one will be blocked. The other threads get a chance to run # from time to time, using the periodic action GILReleaseAction. -from rpython.rlib import rthread as thread +from rpython.rlib import rthread from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.executioncontext import PeriodicAsyncAction from pypy.module.thread.threadlocals import OSThreadLocals @@ -25,7 +25,7 @@ use_bytecode_counter=True) def _initialize_gil(self, space): - if not thread.gil_allocate(): + if not rthread.gil_allocate(): raise wrap_thread_error(space, "can't allocate GIL") def setup_threads(self, space): @@ -72,15 +72,15 @@ # this function must not raise, in such a way that the exception # transformer knows that it cannot raise! e = get_errno() - thread.gil_release() + rthread.gil_release() set_errno(e) before_external_call._gctransformer_hint_cannot_collect_ = True before_external_call._dont_reach_me_in_del_ = True def after_external_call(): e = get_errno() - thread.gil_acquire() - thread.gc_thread_run() + rthread.gil_acquire() + rthread.gc_thread_run() after_thread_switch() set_errno(e) after_external_call._gctransformer_hint_cannot_collect_ = True @@ -97,8 +97,8 @@ # explicitly release the gil, in a way that tries to give more # priority to other threads (as opposed to continuing to run in # the same thread). - if thread.gil_yield_thread(): - thread.gc_thread_run() + if rthread.gil_yield_thread(): + rthread.gc_thread_run() after_thread_switch() do_yield_thread._gctransformer_hint_close_stack_ = True do_yield_thread._dont_reach_me_in_del_ = True diff --git a/pypy/module/thread/os_lock.py b/pypy/module/thread/os_lock.py --- a/pypy/module/thread/os_lock.py +++ b/pypy/module/thread/os_lock.py @@ -2,7 +2,7 @@ Python locks, based on true threading locks provided by the OS. """ -from rpython.rlib import rthread as thread +from rpython.rlib import rthread from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec @@ -27,7 +27,7 @@ ## except: ## pass ## tb = ' '.join(tb) -## msg = '| %6d | %d %s | %s\n' % (thread.get_ident(), n, msg, tb) +## msg = '| %6d | %d %s | %s\n' % (rthread.get_ident(), n, msg, tb) ## sys.stderr.write(msg) @@ -57,8 +57,8 @@ def __init__(self, space): self.space = space try: - self.lock = thread.allocate_lock() - except thread.error: + self.lock = rthread.allocate_lock() + except rthread.error: raise wrap_thread_error(space, "out of resources") @unwrap_spec(blocking=int, timeout=float) @@ -81,7 +81,7 @@ but it needn't be locked by the same thread that unlocks it.""" try: self.lock.release() - except thread.error: + except rthread.error: raise wrap_thread_error(space, "release unlocked lock") def descr_lock_locked(self, space): diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py --- a/pypy/module/thread/os_thread.py +++ b/pypy/module/thread/os_thread.py @@ -3,7 +3,7 @@ """ import os -from rpython.rlib import rthread as thread +from rpython.rlib import rthread from pypy.module.thread.error import wrap_thread_error from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import unwrap_spec, Arguments @@ -65,8 +65,8 @@ def setup(space): if bootstrapper.lock is None: try: - bootstrapper.lock = thread.allocate_lock() - except thread.error: + bootstrapper.lock = rthread.allocate_lock() + except rthread.error: raise wrap_thread_error(space, "can't allocate bootstrap lock") @staticmethod @@ -83,7 +83,7 @@ # Note that when this runs, we already hold the GIL. This is ensured # by rffi's callback mecanism: we are a callback for the # c_thread_start() external function. - thread.gc_thread_start() + rthread.gc_thread_start() space = bootstrapper.space w_callable = bootstrapper.w_callable args = bootstrapper.args @@ -103,7 +103,7 @@ except OSError: pass bootstrapper.nbthreads -= 1 - thread.gc_thread_die() + rthread.gc_thread_die() bootstrap = staticmethod(bootstrap) def acquire(space, w_callable, args): @@ -130,7 +130,7 @@ space.call_args(w_callable, args) except OperationError, e: if not e.match(space, space.w_SystemExit): - ident = thread.get_ident() + ident = rthread.get_ident() where = 'thread %d started by ' % ident e.write_unraisable(space, where, w_callable) e.clear(space) @@ -150,7 +150,7 @@ "Called in the child process after a fork()" space.threadlocals.reinit_threads(space) bootstrapper.reinit() - thread.thread_after_fork() + rthread.thread_after_fork() # Clean the threading module after a fork() w_modules = space.sys.get('modules') @@ -181,12 +181,12 @@ bootstrapper.acquire(space, w_callable, args) try: try: - thread.gc_thread_prepare() # (this has no effect any more) - ident = thread.start_new_thread(bootstrapper.bootstrap, ()) + rthread.gc_thread_prepare() # (this has no effect any more) + ident = rthread.start_new_thread(bootstrapper.bootstrap, ()) except Exception, e: bootstrapper.release() # normally called by the new thread raise - except thread.error: + except rthread.error: raise wrap_thread_error(space, "can't start new thread") return space.wrap(ident) @@ -199,7 +199,7 @@ allocated consecutive numbers starting at 1, this behavior should not be relied upon, and the number should be seen purely as a magic cookie. A thread's identity may be reused for another thread after it exits.""" - ident = thread.get_ident() + ident = rthread.get_ident() return space.wrap(ident) @unwrap_spec(size=int) @@ -225,8 +225,8 @@ if size < 0: raise OperationError(space.w_ValueError, space.wrap("size must be 0 or a positive value")) - old_size = thread.get_stacksize() - error = thread.set_stacksize(size) + old_size = rthread.get_stacksize() + error = rthread.set_stacksize(size) if error == -1: raise operationerrfmt(space.w_ValueError, "size not valid: %d bytes", size) 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 @@ -1,4 +1,4 @@ -from rpython.rlib import rthread as thread +from rpython.rlib import rthread class OSThreadLocals: @@ -9,16 +9,17 @@ def __init__(self): self._valuedict = {} # {thread_ident: ExecutionContext()} + self._signalsenabled = {} # {thread_ident: number-of-times} self._cleanup_() def _cleanup_(self): self._valuedict.clear() - self._mainthreadident = 0 + self._signalsenabled.clear() self._mostrecentkey = 0 # fast minicaching for the common case self._mostrecentvalue = None # fast minicaching for the common case def getvalue(self): - ident = thread.get_ident() + ident = rthread.get_ident() if ident == self._mostrecentkey: result = self._mostrecentvalue else: @@ -30,10 +31,10 @@ return result def setvalue(self, value): - ident = thread.get_ident() + ident = rthread.get_ident() if value is not None: if len(self._valuedict) == 0: - self._mainthreadident = ident + self._signalsenabled[ident] = 1 # the main thread is enabled self._valuedict[ident] = value else: try: @@ -44,8 +45,24 @@ self._mostrecentkey = ident self._mostrecentvalue = value - def ismainthread(self): - return thread.get_ident() == self._mainthreadident + def signals_enabled(self): + return rthread.get_ident() in self._signalsenabled + + def enable_signals(self): + ident = rthread.get_ident() + old = self._signalsenabled.get(ident, 0) + self._signalsenabled[ident] = old + 1 + + def disable_signals(self): + ident = rthread.get_ident() + try: + new = self._signalsenabled[ident] - 1 + except KeyError: + return + if new > 0: + self._signalsenabled[ident] = new + else: + del self._signalsenabled[ident] def getallvalues(self): return self._valuedict @@ -60,4 +77,13 @@ def reinit_threads(self, space): "Called in the child process after a fork()" - self._mainthreadident = thread.get_ident() + # clear the _signalsenabled dictionary for all other threads + # (which are now dead); and for the current thread, force an + # enable_signals() if necessary. That's a hack but I cannot + # figure out a non-hackish way to handle thread+signal+fork :-( + ident = rthread.get_ident() + old = self._signalsenabled.get(ident, 0) + self._signalsenabled.clear() + if old == 0: + old = 1 + self._signalsenabled[ident] = old diff --git a/rpython/jit/codewriter/assembler.py b/rpython/jit/codewriter/assembler.py --- a/rpython/jit/codewriter/assembler.py +++ b/rpython/jit/codewriter/assembler.py @@ -107,7 +107,9 @@ key = (kind, Constant(value)) if key not in self.constants_dict: constants.append(value) - self.constants_dict[key] = 256 - len(constants) + val = 256 - len(constants) + assert val >= 0, "too many constants" + self.constants_dict[key] = val # emit the constant normally, as one byte that is an index in the # list of constants self.code.append(chr(self.constants_dict[key])) diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -476,7 +476,7 @@ get_jitcell_at=None, set_jitcell_at=None, get_printable_location=None, confirm_enter_jit=None, can_never_inline=None, should_unroll_one_iteration=None, - name='jitdriver'): + name='jitdriver', check_untranslated=True): if greens is not None: self.greens = greens self.name = name @@ -511,6 +511,7 @@ self.confirm_enter_jit = confirm_enter_jit self.can_never_inline = can_never_inline self.should_unroll_one_iteration = should_unroll_one_iteration + self.check_untranslated = check_untranslated def _freeze_(self): return True @@ -565,13 +566,15 @@ def jit_merge_point(_self, **livevars): # special-cased by ExtRegistryEntry - _self._check_arguments(livevars) + if _self.check_untranslated: + _self._check_arguments(livevars) def can_enter_jit(_self, **livevars): if _self.autoreds: raise TypeError, "Cannot call can_enter_jit on a driver with reds='auto'" # special-cased by ExtRegistryEntry - _self._check_arguments(livevars) + if _self.check_untranslated: + _self._check_arguments(livevars) def loop_header(self): # special-cased by ExtRegistryEntry diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py --- a/rpython/rlib/rarithmetic.py +++ b/rpython/rlib/rarithmetic.py @@ -630,21 +630,16 @@ uint2singlefloat, singlefloat2uint T = lltype.typeOf(arg) - is_float = False - is_single_float = False if T == lltype.SingleFloat: - T = rffi.UINT - is_single_float = True arg = singlefloat2uint(arg) elif T == lltype.Float: - is_float = True - T = rffi.LONGLONG arg = float2longlong(arg) elif T == lltype.LongFloat: assert False else: # we cannot do arithmetics on small ints arg = widen(arg) + if rffi.sizeof(T) == 1: res = arg elif rffi.sizeof(T) == 2: @@ -667,9 +662,9 @@ (f >> 24) | (g >> 40) | (h >> 56)) else: assert False # unreachable code - if is_single_float: + + if T == lltype.SingleFloat: return uint2singlefloat(rffi.cast(rffi.UINT, res)) - if is_float: - res = rffi.cast(rffi.LONGLONG, res) - return longlong2float(res) + if T == lltype.Float: + return longlong2float(rffi.cast(rffi.LONGLONG, res)) return rffi.cast(T, res) 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 @@ -235,12 +235,12 @@ result.append("".join(l)) @jit.unroll_safe -def pack_float80(result, x, size, be): +def pack_float80(result, x, be): l = [] unsigned = float_pack80(x) for i in range(8): l.append(chr((unsigned[0] >> (i * 8)) & 0xFF)) - for i in range(size - 8): + for i in range(2): l.append(chr((unsigned[1] >> (i * 8)) & 0xFF)) if be: l.reverse() @@ -253,12 +253,14 @@ unsigned |= r_ulonglong(c) << (i * 8) return float_unpack(unsigned, len(s)) -def unpack_float128(s, be): +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[len(s) - 1 - i if be else i]) + c = ord(s[9 - i if be else i]) QQ[0] |= r_ulonglong(c) << (i * 8) - for i in range(8, len(s)): - c = ord(s[len(s) - 1 - i if be else i]) + for i in range(8, 10): + c = ord(s[9 - i if be else i]) QQ[1] |= r_ulonglong(c) << ((i - 8) * 8) return float_unpack80(QQ) diff --git a/rpython/rlib/rstruct/runpack.py b/rpython/rlib/rstruct/runpack.py --- a/rpython/rlib/rstruct/runpack.py +++ b/rpython/rlib/rstruct/runpack.py @@ -46,7 +46,7 @@ def __init__(self, fmt): self.formats = [] self.fmt = fmt - + def operate(self, fmtdesc, repetitions): if fmtdesc.needcount: self.formats.append((fmtdesc, repetitions, None)) @@ -110,5 +110,3 @@ unpacker = create_unpacker(fmt) return unpacker.unpack(input) runpack._annspecialcase_ = 'specialize:arg(0)' - - 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 @@ -1,9 +1,12 @@ -import py, sys +import py +import sys import random import struct -from rpython.rlib.rfloat import isnan -from rpython.rlib.rstruct.ieee import float_pack, float_unpack, float_pack80, float_unpack80 +from rpython.rlib.rstruct import ieee +from rpython.rlib.rfloat import isnan, NAN, INFINITY +from rpython.translator.c.test.test_genc import compile + class TestFloatPacking: def setup_class(cls): @@ -12,17 +15,29 @@ def check_float(self, x): # check roundtrip - Q = float_pack(x, 8) - y = float_unpack(Q, 8) - assert repr(x) == repr(y) + Q = ieee.float_pack(x, 8) + y = ieee.float_unpack(Q, 8) + assert repr(x) == repr(y), '%r != %r, Q=%r' % (x, y, Q) - Q = float_pack80(x) - y = float_unpack80(Q) - 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) # check that packing agrees with the struct module struct_pack8 = struct.unpack('<Q', struct.pack('<d', x))[0] - float_pack8 = float_pack(x, 8) + float_pack8 = ieee.float_pack(x, 8) assert struct_pack8 == float_pack8 # check that packing agrees with the struct module @@ -31,7 +46,7 @@ except OverflowError: struct_pack4 = "overflow" try: - float_pack4 = float_pack(x, 4) + float_pack4 = ieee.float_pack(x, 4) except OverflowError: float_pack4 = "overflow" assert struct_pack4 == float_pack4 @@ -40,16 +55,16 @@ return # if we didn't overflow, try round-tripping the binary32 value - roundtrip = float_pack(float_unpack(float_pack4, 4), 4) + roundtrip = ieee.float_pack(ieee.float_unpack(float_pack4, 4), 4) assert float_pack4 == roundtrip try: - float_pack2 = float_pack(x, 2) + float_pack2 = ieee.float_pack(x, 2) except OverflowError: return - roundtrip = float_pack(float_unpack(float_pack2, 2), 2) - assert (float_pack2,x) == (roundtrip,x) + roundtrip = ieee.float_pack(ieee.float_unpack(float_pack2, 2), 2) + assert (float_pack2, x) == (roundtrip, x) def test_infinities(self): self.check_float(float('inf')) @@ -61,23 +76,23 @@ def test_check_size(self): # these were refactored into separate pack80/unpack80 functions - py.test.raises(ValueError, float_pack, 1.0, 12) - py.test.raises(ValueError, float_pack, 1.0, 16) - py.test.raises(ValueError, float_unpack, 1, 12) - py.test.raises(ValueError, float_unpack, 1, 16) + 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 = float_pack80(float('nan')) - y = float_unpack80(Q) + Q = ieee.float_pack80(float('nan')) + y = ieee.float_unpack80(Q) assert repr(y) == 'nan' - Q = float_pack(float('nan'), 8) - y = float_unpack(Q, 8) + Q = ieee.float_pack(float('nan'), 8) + y = ieee.float_unpack(Q, 8) assert repr(y) == 'nan' - L = float_pack(float('nan'), 4) - z = float_unpack(L, 4) + L = ieee.float_pack(float('nan'), 4) + z = ieee.float_unpack(L, 4) assert repr(z) == 'nan' - L = float_pack(float('nan'), 2) - z = float_unpack(L, 2) + L = ieee.float_pack(float('nan'), 2) + z = ieee.float_unpack(L, 2) assert repr(z) == 'nan' def test_simple(self): @@ -138,22 +153,22 @@ def test_halffloat_exact(self): #testcases generated from numpy.float16(x).view('uint16') - cases = [[0, 0], [10, 18688], [-10, 51456], [10e3, 28898], + cases = [[0, 0], [10, 18688], [-10, 51456], [10e3, 28898], [float('inf'), 31744], [-float('inf'), 64512]] - for c,h in cases: - hbit = float_pack(c, 2) + for c, h in cases: + hbit = ieee.float_pack(c, 2) assert hbit == h - assert c == float_unpack(h, 2) + 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 = float_pack(c, 2) + for c, h, f in cases: + hbit = ieee.float_pack(c, 2) assert hbit == h - assert f == float_unpack(h, 2) + assert f == ieee.float_unpack(h, 2) def test_halffloat_overunderflow(self): import math @@ -161,8 +176,43 @@ [1e-08, 0], [-1e-8, -0.]] for f1, f2 in cases: try: - f_out = float_unpack(float_pack(f1, 2), 2) + 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): + def pack(x, size): + result = [] + ieee.pack_float(result, x, size, False) + l = [] + for x in result: + for c in x: + l.append(str(ord(c))) + return ','.join(l) + c_pack = compile(pack, [float, int]) + + def unpack(s): + l = s.split(',') + s = ''.join([chr(int(x)) for x in l]) + return ieee.unpack_float(s, False) + c_unpack = compile(unpack, [str]) + + def check_roundtrip(x, size): + s = c_pack(x, size) + assert s == pack(x, size) + if not isnan(x): + assert unpack(s) == x + assert c_unpack(s) == x + else: + assert isnan(unpack(s)) + assert isnan(c_unpack(s)) + + for size in [2, 4, 8]: + check_roundtrip(123.4375, size) + check_roundtrip(-123.4375, size) + check_roundtrip(INFINITY, size) + check_roundtrip(NAN, size) diff --git a/rpython/rlib/test/test_rstruct.py b/rpython/rlib/rstruct/test/test_runpack.py rename from rpython/rlib/test/test_rstruct.py rename to rpython/rlib/rstruct/test/test_runpack.py --- a/rpython/rlib/test/test_rstruct.py +++ b/rpython/rlib/rstruct/test/test_runpack.py @@ -1,10 +1,6 @@ - from rpython.rtyper.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin from rpython.rlib.rstruct.runpack import runpack -from rpython.rlib.rstruct import ieee from rpython.rlib.rarithmetic import LONG_BIT -from rpython.rlib.rfloat import INFINITY, NAN, isnan -from rpython.translator.c.test.test_genc import compile import struct class BaseTestRStruct(BaseRtypingTest): @@ -17,11 +13,9 @@ def test_unpack_2(self): data = struct.pack('iiii', 0, 1, 2, 4) - def fn(): a, b, c, d = runpack('iiii', data) return a * 1000 + b * 100 + c * 10 + d - assert fn() == 124 assert self.interpret(fn, []) == 124 @@ -37,36 +31,3 @@ class TestOOType(BaseTestRStruct, OORtypeMixin): pass - -class TestCompiled: - def test_pack_float(self): - def pack(x): - result = [] - ieee.pack_float(result, x, 8, False) - l = [] - for x in result: - for c in x: - l.append(str(ord(c))) - return ','.join(l) - c_pack = compile(pack, [float]) - def unpack(s): - l = s.split(',') - s = ''.join([chr(int(x)) for x in l]) - return ieee.unpack_float(s, False) - c_unpack = compile(unpack, [str]) - - def check_roundtrip(x): - s = c_pack(x) - assert s == pack(x) - if not isnan(x): - assert unpack(s) == x - assert c_unpack(s) == x - else: - assert isnan(unpack(s)) - assert isnan(c_unpack(s)) - - check_roundtrip(123.456) - check_roundtrip(-123.456) - check_roundtrip(INFINITY) - check_roundtrip(NAN) - diff --git a/rpython/rlib/streamio.py b/rpython/rlib/streamio.py --- a/rpython/rlib/streamio.py +++ b/rpython/rlib/streamio.py @@ -795,8 +795,10 @@ self.buflen += len(data) else: if self.buflen: + self.buf.append(data[:p]) self.do_write(''.join(self.buf)) - self.do_write(data[:p]) + else: + self.do_write(data[:p]) self.buf = [data[p:]] self.buflen = len(self.buf[0]) else: diff --git a/rpython/rlib/test/test_rarithmetic.py b/rpython/rlib/test/test_rarithmetic.py --- a/rpython/rlib/test/test_rarithmetic.py +++ b/rpython/rlib/test/test_rarithmetic.py @@ -400,8 +400,8 @@ assert rffi.cast(lltype.Signed, byteswap(rffi.cast(rffi.USHORT, 0x0102))) == 0x0201 assert rffi.cast(lltype.Signed, byteswap(rffi.cast(rffi.INT, 0x01020304))) == 0x04030201 - assert byteswap(rffi.cast(rffi.ULONGLONG, 0x0102030405060708L)) == 0x0807060504030201L - assert byteswap(rffi.cast(rffi.LONGLONG, 0x0102030405060708L)) == 0x0807060504030201L + assert byteswap(r_ulonglong(0x0102030405060708L)) == r_ulonglong(0x0807060504030201L) + assert byteswap(r_longlong(0x0102030405060708L)) == r_longlong(0x0807060504030201L) assert ((byteswap(2.3) - 1.903598566252326e+185) / 1e185) < 0.000001 assert (rffi.cast(lltype.Float, byteswap(rffi.cast(lltype.SingleFloat, 2.3))) - 4.173496037651603e-08) < 1e-16 diff --git a/rpython/rtyper/lltypesystem/rlist.py b/rpython/rtyper/lltypesystem/rlist.py --- a/rpython/rtyper/lltypesystem/rlist.py +++ b/rpython/rtyper/lltypesystem/rlist.py @@ -246,6 +246,7 @@ of the list to be 'newsize'.""" _ll_list_resize_really(l, newsize, False) + @jit.look_inside_iff(lambda l, newsize: jit.isconstant(len(l.items)) and jit.isconstant(newsize)) @jit.oopspec("list._resize_ge(l, newsize)") def _ll_list_resize_ge(l, newsize): _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit