1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <assert.h>
6#include <zircon/process.h>
7#include <zircon/syscalls.h>
8#include <unittest/unittest.h>
9#include <stdio.h>
10#include <zircon/compiler.h>
11
12extern void thread_entry(uintptr_t arg);
13
14int print_fail(void) {
15    EXPECT_TRUE(false, "Failed");
16    zx_thread_exit();
17    return 1; // Not reached
18}
19
20// create a thread using the raw zircon api.
21// cannot use a higher level api because they'll use trampoline functions that'll trash
22// registers on entry.
23zx_status_t raw_thread_create(void (*thread_entry)(uintptr_t arg), uintptr_t arg,
24                               zx_handle_t* out)
25{
26    // preallocated stack to satisfy the thread we create
27    static uint8_t stack[1024] __ALIGNED(16);
28
29    zx_handle_t handle;
30    zx_status_t status = zx_thread_create(zx_process_self(), "", 0, 0, &handle);
31    if (status < 0)
32        return status;
33
34    status = zx_thread_start(handle, (uintptr_t)thread_entry,
35                             (uintptr_t)stack + sizeof(stack),
36                             arg, 0);
37    if (status < 0) {
38        zx_handle_close(handle);
39        return status;
40    }
41
42    *out = handle;
43    return ZX_OK;
44}
45
46bool tis_test(void) {
47    BEGIN_TEST;
48    uintptr_t arg = 0x1234567890abcdef;
49    zx_handle_t handle = ZX_HANDLE_INVALID;
50    zx_status_t status = raw_thread_create(thread_entry, arg, & handle);
51    ASSERT_EQ(status, ZX_OK, "Error while thread creation");
52
53    status = zx_object_wait_one(handle, ZX_THREAD_TERMINATED, ZX_TIME_INFINITE, NULL);
54    ASSERT_GE(status, 0, "Error while thread wait");
55    END_TEST;
56}
57
58BEGIN_TEST_CASE(tis_tests)
59RUN_TEST(tis_test)
60END_TEST_CASE(tis_tests)
61
62int main(int argc, char** argv) {
63    return unittest_run_all_tests(argc, argv) ? 0 : -1;
64}
65