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 <errno.h>
6 #include <inttypes.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <threads.h>
10
11 #include <zircon/syscalls.h>
12 #include <zircon/threads.h>
13 #include <unittest/unittest.h>
14
15 static volatile int threads_done[7];
16
thread_entry(void * arg)17 static int thread_entry(void* arg) {
18 int thread_number = (int)(intptr_t)arg;
19 errno = thread_number;
20 unittest_printf("thread %d sleeping for .1 seconds\n", thread_number);
21 zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
22 EXPECT_EQ(errno, thread_number, "errno changed by someone!");
23 threads_done[thread_number] = 1;
24 return thread_number;
25 }
26
c11_thread_test(void)27 bool c11_thread_test(void) {
28 BEGIN_TEST;
29
30 thrd_t thread;
31 int return_value = 99;
32
33 unittest_printf("Welcome to thread test!\n");
34
35 memset((void*)threads_done, 0, sizeof(threads_done));
36 for (int i = 0; i != 4; ++i) {
37 int return_value = 99;
38 int ret = thrd_create_with_name(&thread, thread_entry, (void*)(intptr_t)i, "c11 thread test");
39 ASSERT_EQ(ret, thrd_success, "Error while creating thread");
40
41 ret = thrd_join(thread, &return_value);
42 ASSERT_EQ(ret, thrd_success, "Error while thread join");
43 ASSERT_EQ(return_value, i, "Incorrect return from thread");
44 }
45
46 unittest_printf("Attempting to create thread with a null name. This should succeed\n");
47 int ret = thrd_create_with_name(&thread, thread_entry, (void*)(intptr_t)4, NULL);
48 ASSERT_EQ(ret, thrd_success, "Error returned from thread creation");
49 zx_handle_t handle = thrd_get_zx_handle(thread);
50 ASSERT_NE(handle, ZX_HANDLE_INVALID, "got invalid thread handle");
51 // Prove this is a valid handle by duplicating it.
52 zx_handle_t dup_handle;
53 zx_status_t status = zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, &dup_handle);
54 ASSERT_EQ(status, 0, "failed to duplicate thread handle");
55
56 ret = thrd_join(thread, &return_value);
57 ASSERT_EQ(ret, thrd_success, "Error while thread join");
58 ASSERT_EQ(zx_handle_close(dup_handle), ZX_OK, "failed to close duplicate handle");
59 ASSERT_EQ(return_value, 4, "Incorrect return from thread");
60
61 ret = thrd_create_with_name(&thread, thread_entry, (void*)(intptr_t)5, NULL);
62 ASSERT_EQ(ret, thrd_success, "Error returned from thread creation");
63 ret = thrd_detach(thread);
64 ASSERT_EQ(ret, thrd_success, "Error while thread detach");
65
66 while (!threads_done[5])
67 zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
68
69 thread_entry((void*)(intptr_t)6);
70 ASSERT_TRUE(threads_done[6], "All threads should have completed");
71
72 END_TEST;
73 }
74
long_name_succeeds(void)75 bool long_name_succeeds(void) {
76 BEGIN_TEST;
77
78 // Creating a thread with a super long name should succeed.
79 static const char long_name[] =
80 "0123456789012345678901234567890123456789"
81 "0123456789012345678901234567890123456789";
82 ASSERT_GT(strlen(long_name), (size_t)ZX_MAX_NAME_LEN-1,
83 "too short to truncate");
84
85 thrd_t thread;
86 int ret = thrd_create_with_name(
87 &thread, thread_entry, (void*)(intptr_t)0, long_name);
88 ASSERT_EQ(ret, thrd_success, "long name should have succeeded");
89
90 // Clean up.
91 int return_value;
92 EXPECT_EQ(thrd_join(thread, &return_value), thrd_success, "");
93 END_TEST;
94 }
95
detach_thrd(void * arg)96 static int detach_thrd(void* arg) {
97 BEGIN_HELPER;
98 thrd_t* thrd = (thrd_t*) arg;
99 EXPECT_EQ(thrd_detach(*thrd), 0, "");
100 free(thrd);
101 END_HELPER;
102 }
103
detach_self_test(void)104 bool detach_self_test(void) {
105 BEGIN_TEST;
106
107 for (size_t i = 0; i < 1000; i++) {
108 thrd_t* thrd = calloc(sizeof(thrd_t), 1);
109 ASSERT_NONNULL(thrd, "");
110 ASSERT_EQ(thrd_create(thrd, detach_thrd, thrd), 0, "");
111 }
112
113 END_TEST;
114 }
115
116 BEGIN_TEST_CASE(c11_thread_tests)
RUN_TEST(c11_thread_test)117 RUN_TEST(c11_thread_test)
118 RUN_TEST(long_name_succeeds)
119 RUN_TEST(detach_self_test)
120 END_TEST_CASE(c11_thread_tests)
121
122 #ifndef BUILD_COMBINED_TESTS
123 int main(int argc, char** argv) {
124 return unittest_run_all_tests(argc, argv) ? 0 : -1;
125 }
126 #endif
127