xref: /llvm-project/lldb/test/API/functionalities/thread/state/TestThreadStates.py (revision 0f17d9a28c40eebd42c83956e2a7b5186c1814d7)
1"""
2Test thread states.
3"""
4
5
6import unittest
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13class ThreadStateTestCase(TestBase):
14    @expectedFailureAll(
15        oslist=["linux"],
16        bugnumber="llvm.org/pr15824 thread states not properly maintained",
17    )
18    @skipIfDarwin  # llvm.org/pr15824 thread states not properly maintained and <rdar://problem/28557237>
19    @expectedFailureAll(
20        oslist=["freebsd"],
21        bugnumber="llvm.org/pr18190 thread states not properly maintained",
22    )
23    @expectedFailureNetBSD
24    def test_state_after_breakpoint(self):
25        """Test thread state after breakpoint."""
26        self.build()
27        self.thread_state_after_breakpoint_test()
28
29    @skipIfDarwin  # 'llvm.org/pr23669', cause Python crash randomly
30    @expectedFailureAll(
31        oslist=lldbplatformutil.getDarwinOSTriples(), bugnumber="llvm.org/pr23669"
32    )
33    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24660")
34    def test_state_after_continue(self):
35        """Test thread state after continue."""
36        self.build()
37        self.thread_state_after_continue_test()
38
39    @skipIfDarwin  # 'llvm.org/pr23669', cause Python crash randomly
40    @expectedFailureDarwin("llvm.org/pr23669")
41    @expectedFailureNetBSD
42    # This actually passes on Windows on Arm but it's hard to describe that
43    # and xfail it everywhere else.
44    @skipIfWindows
45    # thread states not properly maintained
46    @unittest.expectedFailure  # llvm.org/pr16712
47    def test_state_after_expression(self):
48        """Test thread state after expression."""
49        self.build()
50        self.thread_state_after_expression_test()
51
52    # thread states not properly maintained
53    @unittest.expectedFailure  # llvm.org/pr15824 and <rdar://problem/28557237>
54    @expectedFailureAll(
55        oslist=["windows"],
56        bugnumber="llvm.org/pr24668: Breakpoints not resolved correctly",
57    )
58    @skipIfDarwin  # llvm.org/pr15824 thread states not properly maintained and <rdar://problem/28557237>
59    @expectedFailureNetBSD
60    def test_process_state(self):
61        """Test thread states (comprehensive)."""
62        self.build()
63        self.thread_states_test()
64
65    def setUp(self):
66        # Call super's setUp().
67        TestBase.setUp(self)
68        # Find the line numbers for our breakpoints.
69        self.break_1 = line_number("main.cpp", "// Set first breakpoint here")
70        self.break_2 = line_number("main.cpp", "// Set second breakpoint here")
71
72    def thread_state_after_breakpoint_test(self):
73        """Test thread state after breakpoint."""
74        exe = self.getBuildArtifact("a.out")
75        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
76
77        # This should create a breakpoint in the main thread.
78        bp = lldbutil.run_break_set_by_file_and_line(
79            self, "main.cpp", self.break_1, num_expected_locations=1
80        )
81
82        # Run the program.
83        self.runCmd("run", RUN_SUCCEEDED)
84
85        # Get the target process
86        target = self.dbg.GetSelectedTarget()
87        process = target.GetProcess()
88
89        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
90        self.assertIsNotNone(thread)
91
92        # Make sure the thread is in the stopped state.
93        self.assertTrue(
94            thread.IsStopped(), "Thread state isn't 'stopped' during breakpoint 1."
95        )
96        self.assertFalse(
97            thread.IsSuspended(), "Thread state is 'suspended' during breakpoint 1."
98        )
99
100        # Kill the process
101        self.runCmd("process kill")
102
103    def wait_for_running_event(self, process):
104        listener = self.dbg.GetListener()
105        lldbutil.expect_state_changes(self, listener, process, [lldb.eStateRunning])
106
107    def thread_state_after_continue_test(self):
108        """Test thread state after continue."""
109        exe = self.getBuildArtifact("a.out")
110        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
111
112        # This should create a breakpoint in the main thread.
113        lldbutil.run_break_set_by_file_and_line(
114            self, "main.cpp", self.break_1, num_expected_locations=1
115        )
116        lldbutil.run_break_set_by_file_and_line(
117            self, "main.cpp", self.break_2, num_expected_locations=1
118        )
119
120        # Run the program.
121        self.runCmd("run", RUN_SUCCEEDED)
122
123        # Get the target process
124        target = self.dbg.GetSelectedTarget()
125        process = target.GetProcess()
126
127        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
128        self.assertIsNotNone(thread)
129
130        # Continue, the inferior will go into an infinite loop waiting for
131        # 'g_test' to change.
132        self.dbg.SetAsync(True)
133        self.runCmd("continue")
134        self.wait_for_running_event(process)
135
136        # Check the thread state. It should be running.
137        self.assertFalse(
138            thread.IsStopped(), "Thread state is 'stopped' when it should be running."
139        )
140        self.assertFalse(
141            thread.IsSuspended(),
142            "Thread state is 'suspended' when it should be running.",
143        )
144
145        # Go back to synchronous interactions
146        self.dbg.SetAsync(False)
147
148        # Kill the process
149        self.runCmd("process kill")
150
151    def thread_state_after_expression_test(self):
152        """Test thread state after expression."""
153        exe = self.getBuildArtifact("a.out")
154        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
155
156        # This should create a breakpoint in the main thread.
157        lldbutil.run_break_set_by_file_and_line(
158            self, "main.cpp", self.break_1, num_expected_locations=1
159        )
160        lldbutil.run_break_set_by_file_and_line(
161            self, "main.cpp", self.break_2, num_expected_locations=1
162        )
163
164        # Run the program.
165        self.runCmd("run", RUN_SUCCEEDED)
166
167        # Get the target process
168        target = self.dbg.GetSelectedTarget()
169        process = target.GetProcess()
170
171        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
172        self.assertIsNotNone(thread)
173
174        # Get the inferior out of its loop
175        self.runCmd("expression g_test = 1")
176
177        # Check the thread state
178        self.assertTrue(
179            thread.IsStopped(),
180            "Thread state isn't 'stopped' after expression evaluation.",
181        )
182        self.assertFalse(
183            thread.IsSuspended(),
184            "Thread state is 'suspended' after expression evaluation.",
185        )
186
187        # Let the process run to completion
188        self.runCmd("process continue")
189
190    @expectedFailureAll(
191        oslist=["windows"],
192        bugnumber="llvm.org/pr24668: Breakpoints not resolved correctly",
193    )
194    @skipIfDarwin  # llvm.org/pr15824 thread states not properly maintained and <rdar://problem/28557237>
195    @no_debug_info_test
196    def test_process_interrupt(self):
197        """Test process interrupt and continue."""
198        self.build()
199        exe = self.getBuildArtifact("a.out")
200        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
201
202        # This should create a breakpoint in the main thread.
203        bpno = lldbutil.run_break_set_by_file_and_line(
204            self, "main.cpp", self.break_1, num_expected_locations=1
205        )
206
207        # Run the program.
208        self.runCmd("run", RUN_SUCCEEDED)
209
210        # Get the target process
211        target = self.dbg.GetSelectedTarget()
212        process = target.GetProcess()
213
214        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
215        self.assertIsNotNone(thread)
216
217        # Remove the breakpoint to avoid the single-step-over-bkpt dance in the
218        # "continue" below
219        self.assertTrue(target.BreakpointDelete(bpno))
220
221        # Continue, the inferior will go into an infinite loop waiting for
222        # 'g_test' to change.
223        self.dbg.SetAsync(True)
224        self.runCmd("continue")
225        self.wait_for_running_event(process)
226
227        # Go back to synchronous interactions
228        self.dbg.SetAsync(False)
229
230        # Stop the process
231        self.runCmd("process interrupt")
232
233        self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonSignal)
234
235        # Get the inferior out of its loop
236        self.runCmd("expression g_test = 1")
237
238        # Run to completion
239        self.runCmd("continue")
240
241    def thread_states_test(self):
242        """Test thread states (comprehensive)."""
243        exe = self.getBuildArtifact("a.out")
244        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
245
246        # This should create a breakpoint in the main thread.
247        lldbutil.run_break_set_by_file_and_line(
248            self, "main.cpp", self.break_1, num_expected_locations=1
249        )
250        lldbutil.run_break_set_by_file_and_line(
251            self, "main.cpp", self.break_2, num_expected_locations=1
252        )
253
254        # Run the program.
255        self.runCmd("run", RUN_SUCCEEDED)
256
257        # Get the target process
258        target = self.dbg.GetSelectedTarget()
259        process = target.GetProcess()
260        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
261        self.assertIsNotNone(thread)
262
263        # Make sure the thread is in the stopped state.
264        self.assertTrue(
265            thread.IsStopped(), "Thread state isn't 'stopped' during breakpoint 1."
266        )
267        self.assertFalse(
268            thread.IsSuspended(), "Thread state is 'suspended' during breakpoint 1."
269        )
270
271        # Continue, the inferior will go into an infinite loop waiting for
272        # 'g_test' to change.
273        self.dbg.SetAsync(True)
274        self.runCmd("continue")
275        self.wait_for_running_event(process)
276
277        # Check the thread state. It should be running.
278        self.assertFalse(
279            thread.IsStopped(), "Thread state is 'stopped' when it should be running."
280        )
281        self.assertFalse(
282            thread.IsSuspended(),
283            "Thread state is 'suspended' when it should be running.",
284        )
285
286        # Go back to synchronous interactions
287        self.dbg.SetAsync(False)
288
289        # Stop the process
290        self.runCmd("process interrupt")
291
292        self.assertStopReason(thread.GetState(), lldb.eStopReasonSignal)
293
294        # Check the thread state
295        self.assertTrue(
296            thread.IsStopped(), "Thread state isn't 'stopped' after process stop."
297        )
298        self.assertFalse(
299            thread.IsSuspended(), "Thread state is 'suspended' after process stop."
300        )
301
302        # Get the inferior out of its loop
303        self.runCmd("expression g_test = 1")
304
305        # Check the thread state
306        self.assertTrue(
307            thread.IsStopped(),
308            "Thread state isn't 'stopped' after expression evaluation.",
309        )
310        self.assertFalse(
311            thread.IsSuspended(),
312            "Thread state is 'suspended' after expression evaluation.",
313        )
314
315        self.assertStopReason(thread.GetState(), lldb.eStopReasonSignal)
316
317        # Run to breakpoint 2
318        self.runCmd("continue")
319
320        self.assertStopReason(thread.GetState(), lldb.eStopReasonBreakpoint)
321
322        # Make sure both threads are stopped
323        self.assertTrue(
324            thread.IsStopped(), "Thread state isn't 'stopped' during breakpoint 2."
325        )
326        self.assertFalse(
327            thread.IsSuspended(), "Thread state is 'suspended' during breakpoint 2."
328        )
329
330        # Run to completion
331        self.runCmd("continue")
332
333        # At this point, the inferior process should have exited.
334        self.assertState(process.GetState(), lldb.eStateExited, PROCESS_EXITED)
335