1 """Test queues inspection SB APIs."""
3 from __future__
import print_function
9 from lldbsuite
.test
.decorators
import *
10 from lldbsuite
.test
.lldbtest
import *
11 from lldbsuite
.test
import lldbutil
14 class TestQueues(TestBase
):
16 mydir
= TestBase
.compute_mydir(__file__
)
19 @add_test_categories(['pyapi'])
20 def test_with_python_api_queues(self
):
21 """Test queues inspection SB APIs."""
26 @add_test_categories(['pyapi'])
27 def test_with_python_api_queues_with_backtrace(self
):
28 """Test queues inspection SB APIs."""
30 self
.queues_with_libBacktraceRecording()
33 # Call super's setUp().
35 # Find the line numbers that we will step to in main:
36 self
.main_source
= "main.c"
38 def check_queue_for_valid_queue_id(self
, queue
):
40 queue
.GetQueueID() != 0, "Check queue %s for valid QueueID (got 0x%x)" %
41 (queue
.GetName(), queue
.GetQueueID()))
43 def check_running_and_pending_items_on_queue(
44 self
, queue
, expected_running
, expected_pending
):
46 queue
.GetNumPendingItems() == expected_pending
,
47 "queue %s should have %d pending items, instead has %d pending items" %
50 (queue
.GetNumPendingItems())))
52 queue
.GetNumRunningItems() == expected_running
,
53 "queue %s should have %d running items, instead has %d running items" %
56 (queue
.GetNumRunningItems())))
58 def describe_threads(self
):
60 for x
in self
.inferior_process
:
62 reason_str
= lldbutil
.stop_reason_to_str(x
.GetStopReason())
64 location
= "\t".join([lldbutil
.get_description(
65 x
.GetFrameAtIndex(i
)) for i
in range(x
.GetNumFrames())])
67 "thread %d: %s (queue id: %s) at\n\t%s" %
68 (id, reason_str
, x
.GetQueueID(), location
))
69 print('\n'.join(desc
))
71 def check_number_of_threads_owned_by_queue(self
, queue
, number_threads
):
72 if (queue
.GetNumThreads() != number_threads
):
73 self
.describe_threads()
76 queue
.GetNumThreads() == number_threads
,
77 "queue %s should have %d thread executing, but has %d" %
80 queue
.GetNumThreads()))
82 def check_queue_kind(self
, queue
, kind
):
83 expected_kind_string
= "Unknown"
84 if kind
== lldb
.eQueueKindSerial
:
85 expected_kind_string
= "Serial queue"
86 if kind
== lldb
.eQueueKindConcurrent
:
87 expected_kind_string
= "Concurrent queue"
88 actual_kind_string
= "Unknown"
89 if queue
.GetKind() == lldb
.eQueueKindSerial
:
90 actual_kind_string
= "Serial queue"
91 if queue
.GetKind() == lldb
.eQueueKindConcurrent
:
92 actual_kind_string
= "Concurrent queue"
94 queue
.GetKind() == kind
,
95 "queue %s is expected to be a %s but it is actually a %s" %
100 def check_queues_threads_match_queue(self
, queue
):
101 for idx
in range(0, queue
.GetNumThreads()):
102 t
= queue
.GetThreadAtIndex(idx
)
104 t
.IsValid(), "Queue %s's thread #%d must be valid" %
105 (queue
.GetName(), idx
))
107 t
.GetQueueID() == queue
.GetQueueID(),
108 "Queue %s has a QueueID of %d but its thread #%d has a QueueID of %d" %
114 t
.GetQueueName() == queue
.GetName(),
115 "Queue %s has a QueueName of %s but its thread #%d has a QueueName of %s" %
121 t
.GetQueue().GetQueueID() == queue
.GetQueueID(),
122 "Thread #%d's Queue's QueueID of %d is not the same as the QueueID of its owning queue %d" %
124 t
.GetQueue().GetQueueID(),
128 """Test queues inspection SB APIs without libBacktraceRecording."""
129 exe
= self
.getBuildArtifact("a.out")
131 target
= self
.dbg
.CreateTarget(exe
)
132 self
.assertTrue(target
, VALID_TARGET
)
133 self
.main_source_spec
= lldb
.SBFileSpec(self
.main_source
)
134 break1
= target
.BreakpointCreateByName("stopper", 'a.out')
135 self
.assertTrue(break1
, VALID_BREAKPOINT
)
136 process
= target
.LaunchSimple(
137 [], None, self
.get_process_working_directory())
138 self
.assertTrue(process
, PROCESS_IS_VALID
)
139 threads
= lldbutil
.get_threads_stopped_at_breakpoint(process
, break1
)
140 if len(threads
) != 1:
141 self
.fail("Failed to stop at breakpoint 1.")
143 self
.inferior_process
= process
145 queue_submittor_1
= lldb
.SBQueue()
146 queue_performer_1
= lldb
.SBQueue()
147 queue_performer_2
= lldb
.SBQueue()
148 queue_performer_3
= lldb
.SBQueue()
149 for idx
in range(0, process
.GetNumQueues()):
150 q
= process
.GetQueueAtIndex(idx
)
151 if q
.GetName() == "com.apple.work_submittor_1":
152 queue_submittor_1
= q
153 if q
.GetName() == "com.apple.work_performer_1":
154 queue_performer_1
= q
155 if q
.GetName() == "com.apple.work_performer_2":
156 queue_performer_2
= q
157 if q
.GetName() == "com.apple.work_performer_3":
158 queue_performer_3
= q
161 queue_submittor_1
.IsValid() and queue_performer_1
.IsValid() and queue_performer_2
.IsValid() and queue_performer_3
.IsValid(),
162 "Got all four expected queues: %s %s %s %s" %
163 (queue_submittor_1
.IsValid(),
164 queue_performer_1
.IsValid(),
165 queue_performer_2
.IsValid(),
166 queue_performer_3
.IsValid()))
168 self
.check_queue_for_valid_queue_id(queue_submittor_1
)
169 self
.check_queue_for_valid_queue_id(queue_performer_1
)
170 self
.check_queue_for_valid_queue_id(queue_performer_2
)
171 self
.check_queue_for_valid_queue_id(queue_performer_3
)
173 self
.check_number_of_threads_owned_by_queue(queue_submittor_1
, 1)
174 self
.check_number_of_threads_owned_by_queue(queue_performer_1
, 1)
175 self
.check_number_of_threads_owned_by_queue(queue_performer_2
, 1)
176 self
.check_number_of_threads_owned_by_queue(queue_performer_3
, 4)
178 self
.check_queue_kind(queue_submittor_1
, lldb
.eQueueKindSerial
)
179 self
.check_queue_kind(queue_performer_1
, lldb
.eQueueKindSerial
)
180 self
.check_queue_kind(queue_performer_2
, lldb
.eQueueKindSerial
)
181 self
.check_queue_kind(queue_performer_3
, lldb
.eQueueKindConcurrent
)
183 self
.check_queues_threads_match_queue(queue_submittor_1
)
184 self
.check_queues_threads_match_queue(queue_performer_1
)
185 self
.check_queues_threads_match_queue(queue_performer_2
)
186 self
.check_queues_threads_match_queue(queue_performer_3
)
188 # We have threads running with all the different dispatch QoS service
189 # levels - find those threads and check that we can get the correct
190 # QoS name for each of them.
192 user_initiated_thread
= lldb
.SBThread()
193 user_interactive_thread
= lldb
.SBThread()
194 utility_thread
= lldb
.SBThread()
195 unspecified_thread
= lldb
.SBThread()
196 background_thread
= lldb
.SBThread()
197 for th
in process
.threads
:
198 if th
.GetName() == "user initiated QoS":
199 user_initiated_thread
= th
200 if th
.GetName() == "user interactive QoS":
201 user_interactive_thread
= th
202 if th
.GetName() == "utility QoS":
204 if th
.GetName() == "unspecified QoS":
205 unspecified_thread
= th
206 if th
.GetName() == "background QoS":
207 background_thread
= th
210 user_initiated_thread
.IsValid(),
211 "Found user initiated QoS thread")
213 user_interactive_thread
.IsValid(),
214 "Found user interactive QoS thread")
215 self
.assertTrue(utility_thread
.IsValid(), "Found utility QoS thread")
217 unspecified_thread
.IsValid(),
218 "Found unspecified QoS thread")
220 background_thread
.IsValid(),
221 "Found background QoS thread")
223 stream
= lldb
.SBStream()
225 user_initiated_thread
.GetInfoItemByPathAsString(
226 "requested_qos.printable_name",
228 "Get QoS printable string for user initiated QoS thread")
230 stream
.GetData() == "User Initiated",
231 "user initiated QoS thread name is valid")
234 user_interactive_thread
.GetInfoItemByPathAsString(
235 "requested_qos.printable_name",
237 "Get QoS printable string for user interactive QoS thread")
239 stream
.GetData() == "User Interactive",
240 "user interactive QoS thread name is valid")
243 utility_thread
.GetInfoItemByPathAsString(
244 "requested_qos.printable_name",
246 "Get QoS printable string for utility QoS thread")
248 stream
.GetData() == "Utility",
249 "utility QoS thread name is valid")
252 unspecified_thread
.GetInfoItemByPathAsString(
253 "requested_qos.printable_name",
255 "Get QoS printable string for unspecified QoS thread")
256 qosName
= stream
.GetData()
258 qosName
== "User Initiated" or qosName
== "Default",
259 "unspecified QoS thread name is valid")
262 background_thread
.GetInfoItemByPathAsString(
263 "requested_qos.printable_name",
265 "Get QoS printable string for background QoS thread")
267 stream
.GetData() == "Background",
268 "background QoS thread name is valid")
270 @skipIfDarwin # rdar://50379398
271 def queues_with_libBacktraceRecording(self
):
272 """Test queues inspection SB APIs with libBacktraceRecording present."""
273 exe
= self
.getBuildArtifact("a.out")
275 if not os
.path
.isfile(
276 '/Applications/Xcode.app/Contents/Developer/usr/lib/libBacktraceRecording.dylib'):
278 "Skipped because libBacktraceRecording.dylib was present on the system.")
280 if not os
.path
.isfile(
281 '/usr/lib/system/introspection/libdispatch.dylib'):
283 "Skipped because introspection libdispatch dylib is not present.")
285 target
= self
.dbg
.CreateTarget(exe
)
286 self
.assertTrue(target
, VALID_TARGET
)
288 self
.main_source_spec
= lldb
.SBFileSpec(self
.main_source
)
290 break1
= target
.BreakpointCreateByName("stopper", 'a.out')
291 self
.assertTrue(break1
, VALID_BREAKPOINT
)
293 # Now launch the process, and do not stop at entry point.
294 libbtr_path
= "/Applications/Xcode.app/Contents/Developer/usr/lib/libBacktraceRecording.dylib"
295 if self
.getArchitecture() in ['arm', 'arm64', 'arm64e', 'arm64_32', 'armv7', 'armv7k']:
296 libbtr_path
= "/Developer/usr/lib/libBacktraceRecording.dylib"
298 process
= target
.LaunchSimple(
301 'DYLD_INSERT_LIBRARIES=%s' % (libbtr_path
),
302 'DYLD_LIBRARY_PATH=/usr/lib/system/introspection'],
303 self
.get_process_working_directory())
305 self
.assertTrue(process
, PROCESS_IS_VALID
)
307 # The stop reason of the thread should be breakpoint.
308 threads
= lldbutil
.get_threads_stopped_at_breakpoint(process
, break1
)
309 if len(threads
) != 1:
310 self
.fail("Failed to stop at breakpoint 1.")
312 self
.inferior_process
= process
314 libbtr_module_filespec
= lldb
.SBFileSpec("libBacktraceRecording.dylib")
315 libbtr_module
= target
.FindModule(libbtr_module_filespec
)
316 if not libbtr_module
.IsValid():
318 "Skipped because libBacktraceRecording.dylib was not loaded into the process.")
321 process
.GetNumQueues() >= 4,
322 "Found the correct number of queues.")
324 queue_submittor_1
= lldb
.SBQueue()
325 queue_performer_1
= lldb
.SBQueue()
326 queue_performer_2
= lldb
.SBQueue()
327 queue_performer_3
= lldb
.SBQueue()
328 for idx
in range(0, process
.GetNumQueues()):
329 q
= process
.GetQueueAtIndex(idx
)
330 if "LLDB_COMMAND_TRACE" in os
.environ
:
331 print("Queue with id %s has name %s" % (q
.GetQueueID(), q
.GetName()))
332 if q
.GetName() == "com.apple.work_submittor_1":
333 queue_submittor_1
= q
334 if q
.GetName() == "com.apple.work_performer_1":
335 queue_performer_1
= q
336 if q
.GetName() == "com.apple.work_performer_2":
337 queue_performer_2
= q
338 if q
.GetName() == "com.apple.work_performer_3":
339 queue_performer_3
= q
340 if q
.GetName() == "com.apple.main-thread":
341 if q
.GetNumThreads() == 0:
342 print("Cannot get thread <=> queue associations")
346 queue_submittor_1
.IsValid() and queue_performer_1
.IsValid() and queue_performer_2
.IsValid() and queue_performer_3
.IsValid(),
347 "Got all four expected queues: %s %s %s %s" %
348 (queue_submittor_1
.IsValid(),
349 queue_performer_1
.IsValid(),
350 queue_performer_2
.IsValid(),
351 queue_performer_3
.IsValid()))
353 self
.check_queue_for_valid_queue_id(queue_submittor_1
)
354 self
.check_queue_for_valid_queue_id(queue_performer_1
)
355 self
.check_queue_for_valid_queue_id(queue_performer_2
)
356 self
.check_queue_for_valid_queue_id(queue_performer_3
)
358 self
.check_running_and_pending_items_on_queue(queue_submittor_1
, 1, 0)
359 self
.check_running_and_pending_items_on_queue(queue_performer_1
, 1, 3)
360 self
.check_running_and_pending_items_on_queue(
361 queue_performer_2
, 1, 9999)
362 self
.check_running_and_pending_items_on_queue(queue_performer_3
, 4, 0)
364 self
.check_number_of_threads_owned_by_queue(queue_submittor_1
, 1)
365 self
.check_number_of_threads_owned_by_queue(queue_performer_1
, 1)
366 self
.check_number_of_threads_owned_by_queue(queue_performer_2
, 1)
367 self
.check_number_of_threads_owned_by_queue(queue_performer_3
, 4)
369 self
.check_queue_kind(queue_submittor_1
, lldb
.eQueueKindSerial
)
370 self
.check_queue_kind(queue_performer_1
, lldb
.eQueueKindSerial
)
371 self
.check_queue_kind(queue_performer_2
, lldb
.eQueueKindSerial
)
372 self
.check_queue_kind(queue_performer_3
, lldb
.eQueueKindConcurrent
)
374 self
.check_queues_threads_match_queue(queue_submittor_1
)
375 self
.check_queues_threads_match_queue(queue_performer_1
)
376 self
.check_queues_threads_match_queue(queue_performer_2
)
377 self
.check_queues_threads_match_queue(queue_performer_3
)
379 self
.assertTrue(queue_performer_2
.GetPendingItemAtIndex(
380 0).IsValid(), "queue 2's pending item #0 is valid")
381 self
.assertTrue(queue_performer_2
.GetPendingItemAtIndex(0).GetAddress().GetSymbol(
382 ).GetName() == "doing_the_work_2", "queue 2's pending item #0 should be doing_the_work_2")
384 queue_performer_2
.GetNumPendingItems() == 9999,
385 "verify that queue 2 still has 9999 pending items")
386 self
.assertTrue(queue_performer_2
.GetPendingItemAtIndex(
387 9998).IsValid(), "queue 2's pending item #9998 is valid")
388 self
.assertTrue(queue_performer_2
.GetPendingItemAtIndex(9998).GetAddress().GetSymbol(
389 ).GetName() == "doing_the_work_2", "queue 2's pending item #0 should be doing_the_work_2")
390 self
.assertTrue(queue_performer_2
.GetPendingItemAtIndex(
391 9999).IsValid() == False, "queue 2's pending item #9999 is invalid")