| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdint.h> |
| #include <stddef.h> |
| |
| #include <test-utils/test-utils.h> |
| #include <unittest/unittest.h> |
| |
| #include "debugger.h" |
| #include "inferior.h" |
| #include "inferior-control.h" |
| #include "utils.h" |
| |
| namespace { |
| |
| struct suspend_on_start_test_state_t { |
| int started_threads = 0; |
| }; |
| |
| bool suspend_on_start_test_handler(zx_handle_t inferior, |
| zx_handle_t port, |
| const zx_port_packet_t* packet, |
| void* handler_arg) { |
| auto* test_state = reinterpret_cast<suspend_on_start_test_state_t*>(handler_arg); |
| BEGIN_HELPER; |
| |
| // This test is supposed to only get an exception and nothing else. |
| ASSERT_TRUE(ZX_PKT_IS_EXCEPTION(packet->type)); |
| |
| zx_koid_t tid = packet->exception.tid; |
| switch (packet->type) { |
| case ZX_EXCP_THREAD_STARTING: |
| unittest_printf("thread %lu starting\n", tid); |
| // We only want to resume the first thread. |
| resume_inferior(inferior, port, tid); |
| test_state->started_threads++; |
| break; |
| case ZX_EXCP_THREAD_EXITING: |
| unittest_printf("thread %lu exiting\n", tid); |
| ASSERT_TRUE(handle_thread_exiting(inferior, port, packet)); |
| break; |
| default: |
| unittest_printf("Unexpected exception %s (%u) on thread %lu\n", |
| tu_exception_to_string(packet->type), packet->type, tid); |
| break; |
| } |
| |
| END_HELPER; |
| } |
| |
| } // namespace |
| |
| bool SuspendOnStartTest() { |
| BEGIN_TEST; |
| |
| launchpad_t* lp; |
| zx_handle_t inferior, channel; |
| if (!setup_inferior(kTestSuspendOnStart, &lp, &inferior, &channel)) |
| return false; |
| |
| // Attach to the inferior now because we want to see thread starting |
| // exceptions. |
| zx_handle_t eport = tu_io_port_create(); |
| size_t max_threads = 2; |
| inferior_data_t* inferior_data = attach_inferior(inferior, eport, max_threads); |
| |
| suspend_on_start_test_state_t test_state = {}; |
| thrd_t wait_inf_thread = start_wait_inf_thread(inferior_data, |
| suspend_on_start_test_handler, |
| &test_state); |
| EXPECT_NE(eport, ZX_HANDLE_INVALID); |
| |
| if (!start_inferior(lp)) |
| return false; |
| |
| // The remaining testing happens at this point as threads start. |
| // This testing is done in |suspend_on_start_test_handler()|. |
| |
| if (!shutdown_inferior(channel, inferior)) |
| return false; |
| |
| // Stop the waiter thread before closing the eport that it's waiting on. |
| join_wait_inf_thread(wait_inf_thread); |
| |
| detach_inferior(inferior_data, true); |
| |
| tu_handle_close(eport); |
| tu_handle_close(channel); |
| tu_handle_close(inferior); |
| |
| END_TEST; |
| } |
| |
| BEGIN_TEST_CASE(suspend_on_start_tests) |
| RUN_TEST(SuspendOnStartTest); |
| END_TEST_CASE(suspend_on_start_tests) |