]> git.saurik.com Git - apple/libpthread.git/blame - tests/join.c
libpthread-454.80.2.tar.gz
[apple/libpthread.git] / tests / join.c
CommitLineData
964d3577
A
1#include <assert.h>
2#include <pthread.h>
3#include <stdint.h>
4#include <stdio.h>
5#include <unistd.h>
a0619f9c 6#include <stdlib.h>
964d3577 7#include <mach/mach.h>
a0619f9c 8#include <libkern/OSAtomicQueue.h>
964d3577 9
a0619f9c 10#include "darwintest_defaults.h"
2546420a 11
964d3577
A
12#define WAITTIME (100 * 1000)
13
14static inline void*
15test(void)
16{
17 static uintptr_t idx;
964d3577
A
18 return (void*)idx;
19}
20
21static void *
22thread(void *param)
23{
24 usleep(WAITTIME);
25 return param;
26}
27
2546420a 28/*
964d3577
A
29static void *
30thread1(void *param)
31{
32 int res;
33 pthread_t p = param;
34
35 usleep(WAITTIME);
36 res = pthread_join(p, NULL);
37 assert(res == 0);
964d3577
A
38 return 0;
39}
2546420a 40*/
964d3577 41
2546420a
A
42T_DECL(join, "pthread_join",
43 T_META_ALL_VALID_ARCHS(YES))
964d3577
A
44{
45 int res;
46 kern_return_t kr;
47 pthread_t p = NULL;
48 void *param, *value;
49
50 param = test();
51 res = pthread_create(&p, NULL, thread, param);
2546420a 52 T_ASSERT_POSIX_ZERO(res, "pthread_create");
964d3577
A
53 value = NULL;
54 res = pthread_join(p, &value);
2546420a
A
55 T_ASSERT_POSIX_ZERO(res, "pthread_join");
56 T_ASSERT_EQ_PTR(param, value, "early join value");
964d3577
A
57
58 param = test();
59 res = pthread_create(&p, NULL, thread, param);
2546420a 60 T_ASSERT_POSIX_ZERO(res, "pthread_create");
964d3577
A
61 usleep(3 * WAITTIME);
62 value = NULL;
63 res = pthread_join(p, &value);
2546420a
A
64 T_ASSERT_POSIX_ZERO(res, "pthread_join");
65 T_ASSERT_EQ_PTR(param, value, "late join value");
964d3577
A
66
67 param = test();
68 res = pthread_create_suspended_np(&p, NULL, thread, param);
2546420a 69 T_ASSERT_POSIX_ZERO(res, "pthread_create_suspended_np");
964d3577 70 kr = thread_resume(pthread_mach_thread_np(p));
2546420a 71 T_ASSERT_EQ_INT(kr, 0, "thread_resume");
964d3577
A
72 value = NULL;
73 res = pthread_join(p, &value);
2546420a
A
74 T_ASSERT_POSIX_ZERO(res, "pthread_join");
75 T_ASSERT_EQ_PTR(param, value, "suspended early join value");
964d3577
A
76
77 param = test();
78 res = pthread_create_suspended_np(&p, NULL, thread, param);
2546420a 79 T_ASSERT_POSIX_ZERO(res, "pthread_create_suspended_np");
964d3577 80 kr = thread_resume(pthread_mach_thread_np(p));
2546420a 81 T_ASSERT_EQ_INT(kr, 0, "thread_resume");
964d3577
A
82 usleep(3 * WAITTIME);
83 value = NULL;
84 res = pthread_join(p, &value);
2546420a
A
85 T_ASSERT_POSIX_ZERO(res, "pthread_join");
86 T_ASSERT_EQ_PTR(param, value, "suspended late join value");
964d3577 87
2546420a
A
88 // This test is supposed to test joining on the main thread. It's not
89 // clear how to express this with libdarwintest for now.
90 /*
964d3577
A
91 test();
92 param = pthread_self();
93 res = pthread_create_suspended_np(&p, NULL, thread1, param);
2546420a 94 T_ASSERT_POSIX_ZERO(res, "pthread_create_suspended_np");
964d3577 95 res = pthread_detach(p);
2546420a 96 T_ASSERT_POSIX_ZERO(res, "pthread_detach");
964d3577 97 kr = thread_resume(pthread_mach_thread_np(p));
2546420a 98 T_ASSERT_EQ_INT(kr, 0, "thread_resume");
964d3577 99 pthread_exit(0);
2546420a
A
100 */
101}
102
103static void *
104thread_stub(__unused void *arg)
105{
106 return NULL;
964d3577
A
107}
108
2546420a
A
109T_DECL(pthread_join_stress, "pthread_join in a loop")
110{
111 for (int i = 0; i < 1000; i++) {
112 pthread_t th[16];
113 for (int j = 0; j < i%16; j++){
114 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_create(&th[j], NULL, thread_stub, NULL), NULL);
115 }
116 for (int j = i%16; j >= 0; j--){
117 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_join(th[j], NULL), NULL);
118 }
119 }
120 T_PASS("Success!");
121}
a0619f9c
A
122
123static pthread_mutex_t join3way_mutex = PTHREAD_MUTEX_INITIALIZER;
124static pthread_cond_t join3way_cond = PTHREAD_COND_INITIALIZER;
125static OSQueueHead join3way_queue = OS_ATOMIC_QUEUE_INIT;
126
127struct join3way_item {
128 pthread_t th;
129 struct join3way_item *next;
130};
131
132static void *
133join3way_joiner(__unused void *arg)
134{
135 pthread_mutex_lock(&join3way_mutex);
136 while (1) {
137 pthread_cond_wait(&join3way_cond, &join3way_mutex);
138 struct join3way_item *item = OSAtomicDequeue(&join3way_queue,
139 offsetof(struct join3way_item, next));
140 pthread_join(item->th, NULL);
141 free(item);
142 }
143 return NULL;
144}
145
146static void *
147join3way_child(__unused void *arg)
148{
149 struct join3way_item *item = malloc(sizeof(struct join3way_item));
150 item->th = pthread_self();
151 item->next = NULL;
152 OSAtomicEnqueue(&join3way_queue, item,
153 offsetof(struct join3way_item, next));
154 pthread_cond_signal(&join3way_cond);
155 return NULL;
156}
157
158static void *
159join3way_creator(__unused void *arg)
160{
161 pthread_attr_t attr;
162 T_QUIET; T_ASSERT_POSIX_ZERO(pthread_attr_init(&attr), "pthread_attr_init");
163 T_ASSERT_POSIX_ZERO(pthread_attr_set_qos_class_np(&attr,
164 QOS_CLASS_USER_INTERACTIVE, 0), "pthread_attr_set_qos_class_np (child)");
165
166 int n = 1000;
167 while (--n > 0) {
168 pthread_t t;
169 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_create(&t, &attr,
170 join3way_child, NULL), "create thread");
171 }
172 T_ASSERT_EQ_INT(n, 0, "created all child threads");
173 return NULL;
174}
175
176T_DECL(pthread_join_3way, "pthread_join from non-parent with priority inversion")
177{
178 pthread_attr_t joinerattr;
179 T_QUIET; T_ASSERT_POSIX_ZERO(pthread_attr_init(&joinerattr),
180 "pthread_attr_init");
181 T_ASSERT_POSIX_ZERO(pthread_attr_set_qos_class_np(&joinerattr,
182 QOS_CLASS_USER_INTERACTIVE, 0), "pthread_attr_set_qos_class_np");
183
184 pthread_t joiner;
185 T_ASSERT_POSIX_SUCCESS(pthread_create(&joiner, &joinerattr, join3way_joiner,
186 NULL), "create joiner thread");
187
188 pthread_attr_t creatorattr;
189 T_QUIET; T_ASSERT_POSIX_ZERO(pthread_attr_init(&creatorattr),
190 "pthread_attr_init");
191 T_ASSERT_POSIX_ZERO(pthread_attr_set_qos_class_np(&joinerattr,
192 QOS_CLASS_BACKGROUND, 0), "pthread_attr_set_qos_class_np (creator)");
193
194 pthread_t creator;
195 T_ASSERT_POSIX_SUCCESS(pthread_create(&creator, &creatorattr,
196 join3way_creator, NULL), "create creator thread");
197
198 pthread_join(creator, NULL);
199}