1// Copyright 2018 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 <unittest/unittest.h>
6
7#include <zircon/syscalls.h>
8#include <zircon/syscalls/object.h>
9
10#define kNumEventpairs 4u
11#define kGap 2u
12
13static bool handle_close_many_test(void) {
14    BEGIN_TEST;
15
16    // Layout: 0 1 2 3 : 0 1 2 3
17    zx_handle_t eventpairs[kNumEventpairs * 2];
18
19    for (size_t idx = 0u; idx < kNumEventpairs; ++idx) {
20        ASSERT_EQ(zx_eventpair_create(0u, &eventpairs[idx], &eventpairs[idx + kNumEventpairs]), ZX_OK, "");
21    }
22
23    ASSERT_EQ(zx_handle_close_many(&eventpairs[0u], kNumEventpairs), ZX_OK, "");
24
25    // Assert that every handle in the preceeding close call was in
26    // fact closed, by waiting on the PEER_CLOSED signal.
27    for (size_t idx = kNumEventpairs; idx < 8u; ++idx) {
28        zx_signals_t signals;
29        ASSERT_EQ(zx_object_wait_one(eventpairs[idx], ZX_EVENTPAIR_PEER_CLOSED,
30                                     0u, &signals), ZX_OK, "");
31        ASSERT_EQ(signals & ZX_EVENTPAIR_PEER_CLOSED, ZX_EVENTPAIR_PEER_CLOSED, "");
32    }
33
34    ASSERT_EQ(zx_handle_close_many(&eventpairs[kNumEventpairs], kNumEventpairs), ZX_OK, "");
35
36    END_TEST;
37}
38
39static bool handle_close_many_invalid_test(void) {
40    BEGIN_TEST;
41
42    // Layout: 0 1 2 3 : invalid invalid : 0 1 2 3
43    zx_handle_t eventpairs[kNumEventpairs * 2 + kGap];
44
45    for (size_t idx = 0u; idx < kNumEventpairs; ++idx) {
46        ASSERT_EQ(zx_eventpair_create(0u, &eventpairs[idx],
47                                      &eventpairs[idx + kNumEventpairs + kGap]), ZX_OK, "");
48    }
49    eventpairs[kNumEventpairs] = ZX_HANDLE_INVALID;
50    eventpairs[kNumEventpairs + 1] = ZX_HANDLE_INVALID;
51
52    ASSERT_EQ(zx_handle_close_many(&eventpairs[0u], kNumEventpairs + kGap), ZX_OK, "");
53
54    // Assert that every handle in the preceeding close call was in
55    // fact closed, by waiting on the PEER_CLOSED signal.
56    for (size_t idx = kNumEventpairs + kGap; idx < 10u; ++idx) {
57        zx_signals_t signals;
58        ASSERT_EQ(zx_object_wait_one(eventpairs[idx], ZX_EVENTPAIR_PEER_CLOSED,
59                                     0u, &signals), ZX_OK, "");
60        ASSERT_EQ(signals & ZX_EVENTPAIR_PEER_CLOSED, ZX_EVENTPAIR_PEER_CLOSED, "");
61    }
62
63    ASSERT_EQ(zx_handle_close_many(&eventpairs[kNumEventpairs + kGap], kNumEventpairs), ZX_OK, "");
64
65    END_TEST;
66}
67
68static bool handle_close_many_duplicate_test(void) {
69    BEGIN_TEST;
70
71    // Layout: 0 1 0 1 2 3 : 0 1 2 3
72    zx_handle_t eventpairs[kNumEventpairs * 2 + kGap];
73
74    for (size_t idx = kGap; idx < kGap + kNumEventpairs; ++idx) {
75        ASSERT_EQ(zx_eventpair_create(0u, &eventpairs[idx],
76                                      &eventpairs[idx + kNumEventpairs]), ZX_OK, "");
77    }
78    // Duplicate the values at the start.
79    eventpairs[0u] = eventpairs[kGap];
80    eventpairs[1u] = eventpairs[kGap + 1u];
81
82    // Note that this returns an error value: the duplicated handles
83    // can't be closed twice. Despite this, all handles were closed.
84    ASSERT_EQ(zx_handle_close_many(&eventpairs[0u], kNumEventpairs + kGap), ZX_ERR_BAD_HANDLE, "");
85
86    // Assert that every handle in the preceeding close call was in
87    // fact closed, by waiting on the PEER_CLOSED signal.
88    for (size_t idx = kNumEventpairs + kGap; idx < 10u; ++idx) {
89        zx_signals_t signals;
90        ASSERT_EQ(zx_object_wait_one(eventpairs[idx], ZX_EVENTPAIR_PEER_CLOSED,
91                                     0u, &signals), ZX_OK, "");
92        ASSERT_EQ(signals & ZX_EVENTPAIR_PEER_CLOSED, ZX_EVENTPAIR_PEER_CLOSED, "");
93    }
94
95    ASSERT_EQ(zx_handle_close_many(&eventpairs[kNumEventpairs + kGap], kNumEventpairs), ZX_OK, "");
96
97    END_TEST;
98}
99
100BEGIN_TEST_CASE(handle_close_tests)
101RUN_TEST(handle_close_many_test)
102RUN_TEST(handle_close_many_invalid_test)
103RUN_TEST(handle_close_many_duplicate_test)
104END_TEST_CASE(handle_close_tests)
105
106#ifndef BUILD_COMBINED_TESTS
107int main(int argc, char** argv) {
108    return unittest_run_all_tests(argc, argv) ? 0 : -1;
109}
110#endif
111