blob: de71e0703c28671dbac400ce87741be7bf0b9b47 [file] [log] [blame]
// 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)