blob: 87fe13c028474a180c5c72d1a3ff12b1ca44fd62 [file] [log] [blame]
Tim Petersd66595f2001-02-04 03:09:53 +00001# Run the _testcapi module tests (tests for the Python/C API): by defn,
Guido van Rossum361c5352001-04-13 17:03:04 +00002# these are all functions _testcapi exports whose name begins with 'test_'.
Tim Peters9ea17ac2001-02-02 05:57:15 +00003
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +00004from __future__ import with_statement
Martin v. Löwis6ce7ed22005-03-03 12:26:35 +00005import sys
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +00006import time
7import random
8import unittest
9import threading
Barry Warsaw04f357c2002-07-23 19:04:11 +000010from test import test_support
Tim Petersd66595f2001-02-04 03:09:53 +000011import _testcapi
Tim Peters9ea17ac2001-02-02 05:57:15 +000012
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000013class TestPendingCalls(unittest.TestCase):
14
15 def pendingcalls_submit(self, l, n):
16 def callback():
17 #this function can be interrupted by thread switching so let's
18 #use an atomic operation
19 l.append(None)
20
21 for i in range(n):
22 time.sleep(random.random()*0.02) #0.01 secs on average
23 #try submitting callback until successful.
24 #rely on regular interrupt to flush queue if we are
25 #unsuccessful.
26 while True:
27 if _testcapi._pending_threadfunc(callback):
28 break;
29
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000030 def pendingcalls_wait(self, l, n, context = None):
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000031 #now, stick around until l[0] has grown to 10
32 count = 0;
33 while len(l) != n:
34 #this busy loop is where we expect to be interrupted to
35 #run our callbacks. Note that callbacks are only run on the
36 #main thread
37 if False and test_support.verbose:
38 print "(%i)"%(len(l),),
39 for i in xrange(1000):
40 a = i*i
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000041 if context and not context.event.is_set():
42 continue
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000043 count += 1
44 self.failUnless(count < 10000,
45 "timeout waiting for %i callbacks, got %i"%(n, len(l)))
46 if False and test_support.verbose:
47 print "(%i)"%(len(l),)
48
49 def test_pendingcalls_threaded(self):
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000050
51 #do every callback on a separate thread
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000052 n = 32 #total callbacks
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000053 threads = []
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000054 class foo(object):pass
55 context = foo()
56 context.l = []
57 context.n = 2 #submits per thread
58 context.nThreads = n / context.n
59 context.nFinished = 0
60 context.lock = threading.Lock()
61 context.event = threading.Event()
62
63 for i in range(context.nThreads):
64 t = threading.Thread(target=self.pendingcalls_thread, args = (context,))
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000065 t.start()
66 threads.append(t)
67
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000068 self.pendingcalls_wait(context.l, n, context)
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000069
70 for t in threads:
71 t.join()
72
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000073 def pendingcalls_thread(self, context):
74 try:
75 self.pendingcalls_submit(context.l, context.n)
76 finally:
77 with context.lock:
78 context.nFinished += 1
79 nFinished = context.nFinished
80 if False and test_support.verbose:
81 print "finished threads: ", nFinished
82 if nFinished == context.nThreads:
83 context.event.set()
84
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000085 def test_pendingcalls_non_threaded(self):
86 #again, just using the main thread, likely they will all be dispathced at
87 #once. It is ok to ask for too many, because we loop until we find a slot.
88 #the loop can be interrupted to dispatch.
89 #there are only 32 dispatch slots, so we go for twice that!
90 l = []
91 n = 64
92 self.pendingcalls_submit(l, n)
93 self.pendingcalls_wait(l, n)
94
95
Tim Peters59b96c12006-03-21 03:58:41 +000096def test_main():
97
98 for name in dir(_testcapi):
99 if name.startswith('test_'):
100 test = getattr(_testcapi, name)
101 if test_support.verbose:
102 print "internal", name
103 try:
104 test()
105 except _testcapi.error:
106 raise test_support.TestFailed, sys.exc_info()[1]
107
108 # some extra thread-state tests driven via _testcapi
109 def TestThreadState():
Tim Peters9ea17ac2001-02-02 05:57:15 +0000110 if test_support.verbose:
Tim Peters59b96c12006-03-21 03:58:41 +0000111 print "auto-thread-state"
Mark Hammond8d98d2c2003-04-19 15:41:53 +0000112
Tim Peters59b96c12006-03-21 03:58:41 +0000113 idents = []
Mark Hammond8d98d2c2003-04-19 15:41:53 +0000114
Tim Peters59b96c12006-03-21 03:58:41 +0000115 def callback():
116 idents.append(thread.get_ident())
Mark Hammond8d98d2c2003-04-19 15:41:53 +0000117
Tim Peters59b96c12006-03-21 03:58:41 +0000118 _testcapi._test_thread_state(callback)
119 a = b = callback
120 time.sleep(1)
121 # Check our main thread is in the list exactly 3 times.
122 if idents.count(thread.get_ident()) != 3:
123 raise test_support.TestFailed, \
124 "Couldn't find main thread correctly in the list"
Mark Hammond8d98d2c2003-04-19 15:41:53 +0000125
Tim Peters59b96c12006-03-21 03:58:41 +0000126 try:
127 _testcapi._test_thread_state
128 have_thread_state = True
129 except AttributeError:
130 have_thread_state = False
Tim Peters0eadaac2003-04-24 16:02:54 +0000131
Tim Peters59b96c12006-03-21 03:58:41 +0000132 if have_thread_state:
Amaury Forgeot d'Arc4b798bd2008-04-08 21:27:42 +0000133 import thread
134 import time
Tim Peters59b96c12006-03-21 03:58:41 +0000135 TestThreadState()
136 import threading
137 t=threading.Thread(target=TestThreadState)
138 t.start()
139 t.join()
Mark Hammond8d98d2c2003-04-19 15:41:53 +0000140
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +0000141 test_support.run_unittest(TestPendingCalls)
142
Tim Peters59b96c12006-03-21 03:58:41 +0000143if __name__ == "__main__":
144 test_main()