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 <stdio.h> 6#include <threads.h> 7#include <time.h> 8 9#include <zircon/syscalls.h> 10#include <unittest/unittest.h> 11 12// This example tests transferring channel handles through channels. To do so, it: 13// Creates two channels, A and B, with handles A0-A1 and B0-B1, respectively 14// Sends message "1" into A0 15// Sends A1 to B0 16// Sends message "2" into A0 17// Reads H from B1 (should receive A1 again, possibly with a new value) 18// Sends "3" into A0 19// Reads from H until empty. Should read "1", "2", "3" in that order. 20bool handle_transfer_test(void) { 21 BEGIN_TEST; 22 zx_handle_t A[2]; 23 zx_status_t status = zx_channel_create(0, A, A + 1); 24 char msg[512]; 25 snprintf(msg, sizeof(msg), "failed to create channel A: %d\n", status); 26 EXPECT_EQ(status, 0, msg); 27 28 zx_handle_t B[2]; 29 status = zx_channel_create(0, B, B + 1); 30 snprintf(msg, sizeof(msg), "failed to create channel B: %d\n", status); 31 EXPECT_EQ(status, 0, msg); 32 33 status = zx_channel_write(A[0], 0u, "1", 1u, NULL, 0u); 34 snprintf(msg, sizeof(msg), "failed to write message \"1\" into A0: %u\n", status); 35 EXPECT_EQ(status, ZX_OK, msg); 36 37 status = zx_channel_write(B[0], 0u, NULL, 0u, &A[1], 1u); 38 snprintf(msg, sizeof(msg), "failed to write message with handle A[1]: %u\n", status); 39 EXPECT_EQ(status, ZX_OK, msg); 40 41 A[1] = ZX_HANDLE_INVALID; 42 status = zx_channel_write(A[0], 0u, "2", 1u, NULL, 0u); 43 snprintf(msg, sizeof(msg), "failed to write message \"2\" into A0: %u\n", status); 44 EXPECT_EQ(status, ZX_OK, msg); 45 46 zx_handle_t H; 47 uint32_t num_bytes = 0u; 48 uint32_t num_handles = 1u; 49 status = zx_channel_read(B[1], 0u, NULL, &H, 0, num_handles, &num_bytes, &num_handles); 50 snprintf(msg, sizeof(msg), "failed to read message from B1: %u\n", status); 51 EXPECT_EQ(status, ZX_OK, msg); 52 53 snprintf(msg, sizeof(msg), "failed to read actual handle value from B1\n"); 54 EXPECT_FALSE((num_handles != 1u || H == ZX_HANDLE_INVALID), msg); 55 56 status = zx_channel_write(A[0], 0u, "3", 1u, NULL, 0u); 57 snprintf(msg, sizeof(msg), "failed to write message \"3\" into A0: %u\n", status); 58 EXPECT_EQ(status, ZX_OK, msg); 59 60 for (int i = 0; i < 3; ++i) { 61 char buf[1]; 62 num_bytes = 1u; 63 num_handles = 0u; 64 status = zx_channel_read(H, 0u, buf, NULL, num_bytes, 0, &num_bytes, &num_handles); 65 snprintf(msg, sizeof(msg), "failed to read message from H: %u\n", status); 66 EXPECT_EQ(status, ZX_OK, msg); 67 unittest_printf("read message: %c\n", buf[0]); 68 } 69 70 zx_handle_close(A[0]); 71 zx_handle_close(B[0]); 72 zx_handle_close(B[1]); 73 zx_handle_close(H); 74 END_TEST; 75} 76 77static int thread(void* arg) { 78 // sleep for 10ms 79 // this is race-prone, but until there's a way to wait for a thread to be 80 // blocked, there's no better way to determine that the other thread has 81 // entered handle_wait_one. 82 struct timespec t = (struct timespec){ 83 .tv_sec = 0, 84 .tv_nsec = 10 * 1000 * 1000, 85 }; 86 nanosleep(&t, NULL); 87 88 // Send A0 through B1 to B0. 89 zx_handle_t* A = (zx_handle_t*)arg; 90 zx_handle_t* B = A + 2; 91 zx_status_t status = zx_channel_write(B[1], 0, NULL, 0u, &A[0], 1); 92 if (status != ZX_OK) { 93 UNITTEST_FAIL_TRACEF("failed to write message with handle A0 to B1: %d\n", status); 94 goto thread_exit; 95 } 96 97 // Read from B0 into H, thus canceling any waits on A0. 98 zx_handle_t H; 99 uint32_t num_handles = 1; 100 status = zx_channel_read(B[0], 0, NULL, &H, 0, num_handles, NULL, &num_handles); 101 if (status != ZX_OK || num_handles < 1) { 102 UNITTEST_FAIL_TRACEF("failed to read message handle H from B0: %d\n", status); 103 } 104 105thread_exit: 106 return 0; 107} 108 109// This tests canceling a wait when a handle is transferred. 110// There are two channels: A0-A1 and B0-B1. 111// A thread is created that sends A0 from B1 to B0. 112// main() waits on A0. 113// The thread then reads from B0, which should cancel the wait in main(). 114// See [ZX-103]. 115bool handle_transfer_cancel_wait_test(void) { 116 BEGIN_TEST; 117 zx_handle_t A[4]; 118 zx_handle_t* B = &A[2]; 119 zx_status_t status = zx_channel_create(0, A, A + 1); 120 char msg[512]; 121 snprintf(msg, sizeof(msg), "failed to create channel A[0,1]: %d\n", status); 122 EXPECT_EQ(status, 0, msg); 123 status = zx_channel_create(0, B, B + 1); 124 snprintf(msg, sizeof(msg), "failed to create channel B[0,1]: %d\n", status); 125 EXPECT_EQ(status, 0, msg); 126 127 thrd_t thr; 128 int ret = thrd_create_with_name(&thr, thread, A, "write thread"); 129 EXPECT_EQ(ret, thrd_success, "failed to create write thread"); 130 131 zx_signals_t signals = ZX_CHANNEL_PEER_CLOSED; 132 status = zx_object_wait_one(A[0], signals, zx_deadline_after(ZX_SEC(1)), NULL); 133 EXPECT_NE(ZX_ERR_TIMED_OUT, status, "failed to complete wait when handle transferred"); 134 135 thrd_join(thr, NULL); 136 zx_handle_close(B[1]); 137 zx_handle_close(B[0]); 138 zx_handle_close(A[1]); 139 zx_handle_close(A[0]); 140 END_TEST; 141} 142 143BEGIN_TEST_CASE(handle_transfer_tests) 144RUN_TEST(handle_transfer_test) 145RUN_TEST(handle_transfer_cancel_wait_test) 146END_TEST_CASE(handle_transfer_tests) 147 148#ifndef BUILD_COMBINED_TESTS 149int main(int argc, char** argv) { 150 return unittest_run_all_tests(argc, argv) ? 0 : -1; 151} 152#endif 153