summaryrefslogtreecommitdiffstats
path: root/Lib/test/test__xxsubinterpreters.py
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2018-02-20 23:30:17 (GMT)
committerGitHub <noreply@github.com>2018-02-20 23:30:17 (GMT)
commitf53d9f2778a87bdd48eb9030f782a4ebf9e7622f (patch)
tree42d0046cdda94825c800ed17db78f85c79d50bbf /Lib/test/test__xxsubinterpreters.py
parent80d20b918bd8a882043c493a7f958333ecb41727 (diff)
downloadcpython-f53d9f2778a87bdd48eb9030f782a4ebf9e7622f.zip
cpython-f53d9f2778a87bdd48eb9030f782a4ebf9e7622f.tar.gz
cpython-f53d9f2778a87bdd48eb9030f782a4ebf9e7622f.tar.bz2
bpo-32604: Swap threads only if the interpreter is different. (gh-5778)
The CPython runtime assumes that there is a one-to-one relationship (for a given interpreter) between PyThreadState and OS threads. Sending and receiving on a channel in the same interpreter was causing crashes because of this (specifically due to a check in PyThreadState_Swap()). The solution is to not switch threads if the interpreter is the same.
Diffstat (limited to 'Lib/test/test__xxsubinterpreters.py')
-rw-r--r--Lib/test/test__xxsubinterpreters.py49
1 files changed, 49 insertions, 0 deletions
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index d280270..397d359 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -3,6 +3,7 @@ import os
import pickle
from textwrap import dedent, indent
import threading
+import time
import unittest
from test import support
@@ -1147,6 +1148,54 @@ class ChannelTests(TestBase):
self.assertEqual(obj, b'spam')
+ def test_send_recv_different_threads(self):
+ cid = interpreters.channel_create()
+
+ def f():
+ while True:
+ try:
+ obj = interpreters.channel_recv(cid)
+ break
+ except interpreters.ChannelEmptyError:
+ time.sleep(0.1)
+ interpreters.channel_send(cid, obj)
+ t = threading.Thread(target=f)
+ t.start()
+
+ interpreters.channel_send(cid, b'spam')
+ t.join()
+ obj = interpreters.channel_recv(cid)
+
+ self.assertEqual(obj, b'spam')
+
+ def test_send_recv_different_interpreters_and_threads(self):
+ cid = interpreters.channel_create()
+ id1 = interpreters.create()
+ out = None
+
+ def f():
+ nonlocal out
+ out = _run_output(id1, dedent(f"""
+ import time
+ import _xxsubinterpreters as _interpreters
+ while True:
+ try:
+ obj = _interpreters.channel_recv({int(cid)})
+ break
+ except _interpreters.ChannelEmptyError:
+ time.sleep(0.1)
+ assert(obj == b'spam')
+ _interpreters.channel_send({int(cid)}, b'eggs')
+ """))
+ t = threading.Thread(target=f)
+ t.start()
+
+ interpreters.channel_send(cid, b'spam')
+ t.join()
+ obj = interpreters.channel_recv(cid)
+
+ self.assertEqual(obj, b'eggs')
+
def test_send_not_found(self):
with self.assertRaises(interpreters.ChannelNotFoundError):
interpreters.channel_send(10, b'spam')