mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
Merged revisions 68425,68461,68498 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r68425 | benjamin.peterson | 2009-01-08 20:56:32 -0600 (Thu, 08 Jan 2009) | 1 line fix markup ........ r68461 | kristjan.jonsson | 2009-01-09 15:35:16 -0600 (Fri, 09 Jan 2009) | 2 lines Issue 4293: Make Py_AddPendingCall() thread safe Add test cases and documentation ........ r68498 | benjamin.peterson | 2009-01-10 13:08:49 -0600 (Sat, 10 Jan 2009) | 1 line fix encoding ........
This commit is contained in:
parent
f343e01c17
commit
a54c9090ac
4 changed files with 158 additions and 5 deletions
|
@ -2,10 +2,14 @@
|
|||
# these are all functions _testcapi exports whose name begins with 'test_'.
|
||||
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import unittest
|
||||
import threading
|
||||
from test import support
|
||||
import _testcapi
|
||||
|
||||
|
||||
def testfunction(self):
|
||||
"""some doc"""
|
||||
return self
|
||||
|
@ -28,6 +32,67 @@ class CAPITest(unittest.TestCase):
|
|||
self.assertRaises(AttributeError, setattr, inst.testfunction, "attribute", "test")
|
||||
|
||||
|
||||
class TestPendingCalls(unittest.TestCase):
|
||||
|
||||
def pendingcalls_submit(self, l, n):
|
||||
def callback():
|
||||
#this function can be interrupted by thread switching so let's
|
||||
#use an atomic operation
|
||||
l.append(None)
|
||||
|
||||
for i in range(n):
|
||||
time.sleep(random.random()*0.02) #0.01 secs on average
|
||||
#try submitting callback until successful.
|
||||
#rely on regular interrupt to flush queue if we are
|
||||
#unsuccessful.
|
||||
while True:
|
||||
if _testcapi._pending_threadfunc(callback):
|
||||
break;
|
||||
|
||||
def pendingcalls_wait(self, l, n):
|
||||
#now, stick around until l[0] has grown to 10
|
||||
count = 0;
|
||||
while len(l) != n:
|
||||
#this busy loop is where we expect to be interrupted to
|
||||
#run our callbacks. Note that callbacks are only run on the
|
||||
#main thread
|
||||
if False and test_support.verbose:
|
||||
print("(%i)"%(len(l),),)
|
||||
for i in range(1000):
|
||||
a = i*i
|
||||
count += 1
|
||||
self.failUnless(count < 10000,
|
||||
"timeout waiting for %i callbacks, got %i"%(n, len(l)))
|
||||
if False and test_support.verbose:
|
||||
print("(%i)"%(len(l),))
|
||||
|
||||
def test_pendingcalls_threaded(self):
|
||||
l = []
|
||||
|
||||
#do every callback on a separate thread
|
||||
n = 32
|
||||
threads = []
|
||||
for i in range(n):
|
||||
t = threading.Thread(target=self.pendingcalls_submit, args = (l, 1))
|
||||
t.start()
|
||||
threads.append(t)
|
||||
|
||||
self.pendingcalls_wait(l, n)
|
||||
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
def test_pendingcalls_non_threaded(self):
|
||||
#again, just using the main thread, likely they will all be dispathced at
|
||||
#once. It is ok to ask for too many, because we loop until we find a slot.
|
||||
#the loop can be interrupted to dispatch.
|
||||
#there are only 32 dispatch slots, so we go for twice that!
|
||||
l = []
|
||||
n = 64
|
||||
self.pendingcalls_submit(l, n)
|
||||
self.pendingcalls_wait(l, n)
|
||||
|
||||
|
||||
def test_main():
|
||||
support.run_unittest(CAPITest)
|
||||
|
||||
|
@ -71,6 +136,8 @@ def test_main():
|
|||
t.start()
|
||||
t.join()
|
||||
|
||||
support.run_unittest(TestPendingCalls)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue