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 <stdbool.h>
7
8#include <zircon/syscalls.h>
9#include <zircon/syscalls/object.h>
10#include <zircon/process.h>
11
12#include <unittest/unittest.h>
13
14// Test that VMO handles support user signals
15static bool vmo_signal_sanity_test(void) {
16    BEGIN_TEST;
17
18    zx_handle_t vmo = ZX_HANDLE_INVALID;
19    ASSERT_EQ(zx_vmo_create(4096, 0, &vmo), ZX_OK, "");
20    ASSERT_NE(vmo, ZX_HANDLE_INVALID, "zx_vmo_create() failed");
21
22    zx_signals_t out_signals = 0;
23
24    // This is not timing dependent, if this fails is not a flake.
25    ASSERT_EQ(zx_object_wait_one(
26        vmo, ZX_USER_SIGNAL_0, zx_deadline_after(2), &out_signals), ZX_ERR_TIMED_OUT, "");
27
28    ASSERT_EQ(out_signals, ZX_VMO_ZERO_CHILDREN, "unexpected initial signal set");
29    ASSERT_EQ(zx_object_signal(vmo, 0, ZX_USER_SIGNAL_0), ZX_OK, "");
30    ASSERT_EQ(zx_object_wait_one(
31        vmo, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, &out_signals), ZX_OK, "");
32    ASSERT_EQ(
33        out_signals, ZX_USER_SIGNAL_0 | ZX_VMO_ZERO_CHILDREN,
34        "ZX_USER_SIGNAL_0 not set after successful wait");
35
36    ASSERT_EQ(zx_handle_close(vmo), ZX_OK, "");
37
38    END_TEST;
39}
40
41static zx_status_t vmo_has_no_children(zx_handle_t vmo) {
42    zx_signals_t signals;
43    return zx_object_wait_one(vmo, ZX_VMO_ZERO_CHILDREN, ZX_TIME_INFINITE, &signals);
44}
45
46static zx_status_t vmo_has_children(zx_handle_t vmo) {
47    zx_signals_t signals;
48    zx_status_t res = zx_object_wait_one(
49        vmo, ZX_VMO_ZERO_CHILDREN, zx_deadline_after(2), &signals);
50    return (res == ZX_ERR_TIMED_OUT) ? ZX_OK : res;
51}
52
53static bool vmo_child_signal_clone_test(void) {
54    BEGIN_TEST;
55
56    zx_handle_t vmo = ZX_HANDLE_INVALID;
57    ASSERT_EQ(zx_vmo_create(4096u * 2, 0, &vmo), ZX_OK, "");
58    ASSERT_NE(vmo, ZX_HANDLE_INVALID, "");
59
60    zx_handle_t clone = ZX_HANDLE_INVALID;
61    zx_handle_t clone2 = ZX_HANDLE_INVALID;
62
63    // The waits below with timeout are not timing dependent, if this fails is not a flake.
64
65    for (int ix = 0; ix != 10; ++ix) {
66        ASSERT_EQ(vmo_has_no_children(vmo), ZX_OK, "");
67
68        ASSERT_EQ(zx_vmo_clone(
69            vmo, ZX_VMO_CLONE_COPY_ON_WRITE, 0u, 4096u, &clone), ZX_OK, "");
70
71        ASSERT_EQ(vmo_has_no_children(clone), ZX_OK, "");
72        ASSERT_EQ(vmo_has_children(vmo), ZX_OK, "");
73
74        ASSERT_EQ(zx_vmo_clone(
75            clone, ZX_VMO_CLONE_COPY_ON_WRITE, 0u, 4096u, &clone2), ZX_OK, "");
76
77        ASSERT_EQ(vmo_has_no_children(clone2), ZX_OK, "");
78        ASSERT_EQ(vmo_has_children(clone), ZX_OK, "");
79        ASSERT_EQ(vmo_has_children(vmo), ZX_OK, "");
80
81        ASSERT_EQ(zx_handle_close(clone), ZX_OK, "");
82        ASSERT_EQ(vmo_has_children(vmo), ZX_OK, "");
83        ASSERT_EQ(vmo_has_no_children(clone2), ZX_OK, "");
84
85        ASSERT_EQ(zx_handle_close(clone2), ZX_OK, "");
86    }
87
88    ASSERT_EQ(zx_handle_close(vmo), ZX_OK, "");
89
90    END_TEST;
91}
92
93static bool vmo_child_signal_map_test(void) {
94    BEGIN_TEST;
95
96    zx_handle_t vmo = ZX_HANDLE_INVALID;
97    ASSERT_EQ(zx_vmo_create(4096u * 2, 0, &vmo), ZX_OK, "");
98    ASSERT_NE(vmo, ZX_HANDLE_INVALID, "");
99
100    zx_handle_t clone = ZX_HANDLE_INVALID;
101
102    zx_vm_option_t options = ZX_VM_PERM_READ | ZX_VM_PERM_WRITE;
103
104    for (int ix = 0; ix != 10; ++ix) {
105        ASSERT_EQ(vmo_has_no_children(vmo), ZX_OK, "");
106
107        ASSERT_EQ(zx_vmo_clone(
108            vmo, ZX_VMO_CLONE_COPY_ON_WRITE, 0u, 4096u, &clone), ZX_OK, "");
109
110        uintptr_t addr = 0;
111        ASSERT_EQ(zx_vmar_map(
112            zx_vmar_root_self(), options, 0u, clone, 0, 4096u, &addr), ZX_OK, "");
113
114        ASSERT_EQ(vmo_has_children(vmo), ZX_OK, "");
115
116        ASSERT_EQ(zx_handle_close(clone), ZX_OK, "");
117
118        ASSERT_EQ(vmo_has_children(vmo), ZX_OK, "");
119
120        ASSERT_EQ(zx_vmar_unmap(zx_vmar_root_self(), addr, 4096u), ZX_OK, "");
121    }
122
123    ASSERT_EQ(zx_handle_close(vmo), ZX_OK, "");
124
125    END_TEST;
126}
127
128BEGIN_TEST_CASE(vmo_signal_tests)
129RUN_TEST(vmo_signal_sanity_test)
130RUN_TEST(vmo_child_signal_clone_test)
131RUN_TEST(vmo_child_signal_map_test)
132END_TEST_CASE(vmo_signal_tests)
133
134#ifndef BUILD_COMBINED_TESTS
135int main(int argc, char** argv) {
136    return unittest_run_all_tests(argc, argv) ? 0 : -1;
137}
138#endif
139