| @@ -1,1311 +1,1318 @@ | | | @@ -1,1311 +1,1318 @@ |
1 | /* $NetBSD: pthread.c,v 1.126 2012/03/02 18:06:05 joerg Exp $ */ | | 1 | /* $NetBSD: pthread.c,v 1.127 2012/03/08 16:33:45 joerg Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Nathan J. Williams and Andrew Doran. | | 8 | * by Nathan J. Williams and Andrew Doran. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __RCSID("$NetBSD: pthread.c,v 1.126 2012/03/02 18:06:05 joerg Exp $"); | | 33 | __RCSID("$NetBSD: pthread.c,v 1.127 2012/03/08 16:33:45 joerg Exp $"); |
34 | | | 34 | |
35 | #define __EXPOSE_STACK 1 | | 35 | #define __EXPOSE_STACK 1 |
36 | | | 36 | |
37 | #include <sys/param.h> | | 37 | #include <sys/param.h> |
38 | #include <sys/exec_elf.h> | | 38 | #include <sys/exec_elf.h> |
39 | #include <sys/mman.h> | | 39 | #include <sys/mman.h> |
40 | #include <sys/sysctl.h> | | 40 | #include <sys/sysctl.h> |
41 | #include <sys/lwpctl.h> | | 41 | #include <sys/lwpctl.h> |
42 | #include <sys/tls.h> | | 42 | #include <sys/tls.h> |
43 | | | 43 | |
44 | #include <assert.h> | | 44 | #include <assert.h> |
45 | #include <dlfcn.h> | | 45 | #include <dlfcn.h> |
46 | #include <err.h> | | 46 | #include <err.h> |
47 | #include <errno.h> | | 47 | #include <errno.h> |
48 | #include <lwp.h> | | 48 | #include <lwp.h> |
49 | #include <signal.h> | | 49 | #include <signal.h> |
50 | #include <stdio.h> | | 50 | #include <stdio.h> |
51 | #include <stdlib.h> | | 51 | #include <stdlib.h> |
52 | #include <string.h> | | 52 | #include <string.h> |
53 | #include <syslog.h> | | 53 | #include <syslog.h> |
54 | #include <ucontext.h> | | 54 | #include <ucontext.h> |
55 | #include <unistd.h> | | 55 | #include <unistd.h> |
56 | #include <sched.h> | | 56 | #include <sched.h> |
57 | | | 57 | |
58 | #include "pthread.h" | | 58 | #include "pthread.h" |
59 | #include "pthread_int.h" | | 59 | #include "pthread_int.h" |
60 | | | 60 | |
61 | pthread_rwlock_t pthread__alltree_lock = PTHREAD_RWLOCK_INITIALIZER; | | 61 | pthread_rwlock_t pthread__alltree_lock = PTHREAD_RWLOCK_INITIALIZER; |
62 | RB_HEAD(__pthread__alltree, __pthread_st) pthread__alltree; | | 62 | RB_HEAD(__pthread__alltree, __pthread_st) pthread__alltree; |
63 | | | 63 | |
64 | #ifndef lint | | 64 | #ifndef lint |
65 | static int pthread__cmp(struct __pthread_st *, struct __pthread_st *); | | 65 | static int pthread__cmp(struct __pthread_st *, struct __pthread_st *); |
66 | RB_PROTOTYPE_STATIC(__pthread__alltree, __pthread_st, pt_alltree, pthread__cmp) | | 66 | RB_PROTOTYPE_STATIC(__pthread__alltree, __pthread_st, pt_alltree, pthread__cmp) |
67 | #endif | | 67 | #endif |
68 | | | 68 | |
69 | static void pthread__create_tramp(void *); | | 69 | static void pthread__create_tramp(void *); |
70 | static void pthread__initthread(pthread_t); | | 70 | static void pthread__initthread(pthread_t); |
71 | static void pthread__scrubthread(pthread_t, char *, int); | | 71 | static void pthread__scrubthread(pthread_t, char *, int); |
72 | static void pthread__initmain(pthread_t *); | | 72 | static void pthread__initmain(pthread_t *); |
73 | static void pthread__fork_callback(void); | | 73 | static void pthread__fork_callback(void); |
74 | static void pthread__reap(pthread_t); | | 74 | static void pthread__reap(pthread_t); |
75 | static void pthread__child_callback(void); | | 75 | static void pthread__child_callback(void); |
76 | static void pthread__start(void); | | 76 | static void pthread__start(void); |
77 | | | 77 | |
78 | void pthread__init(void); | | 78 | void pthread__init(void); |
79 | | | 79 | |
80 | int pthread__started; | | 80 | int pthread__started; |
81 | pthread_mutex_t pthread__deadqueue_lock = PTHREAD_MUTEX_INITIALIZER; | | 81 | pthread_mutex_t pthread__deadqueue_lock = PTHREAD_MUTEX_INITIALIZER; |
82 | pthread_queue_t pthread__deadqueue; | | 82 | pthread_queue_t pthread__deadqueue; |
83 | pthread_queue_t pthread__allqueue; | | 83 | pthread_queue_t pthread__allqueue; |
84 | | | 84 | |
85 | static pthread_attr_t pthread_default_attr; | | 85 | static pthread_attr_t pthread_default_attr; |
86 | static lwpctl_t pthread__dummy_lwpctl = { .lc_curcpu = LWPCTL_CPU_NONE }; | | 86 | static lwpctl_t pthread__dummy_lwpctl = { .lc_curcpu = LWPCTL_CPU_NONE }; |
87 | static pthread_t pthread__first; | | 87 | static pthread_t pthread__first; |
88 | | | 88 | |
89 | enum { | | 89 | enum { |
90 | DIAGASSERT_ABORT = 1<<0, | | 90 | DIAGASSERT_ABORT = 1<<0, |
91 | DIAGASSERT_STDERR = 1<<1, | | 91 | DIAGASSERT_STDERR = 1<<1, |
92 | DIAGASSERT_SYSLOG = 1<<2 | | 92 | DIAGASSERT_SYSLOG = 1<<2 |
93 | }; | | 93 | }; |
94 | | | 94 | |
95 | static int pthread__diagassert; | | 95 | static int pthread__diagassert; |
96 | | | 96 | |
97 | int pthread__concurrency; | | 97 | int pthread__concurrency; |
98 | int pthread__nspins; | | 98 | int pthread__nspins; |
99 | int pthread__unpark_max = PTHREAD__UNPARK_MAX; | | 99 | int pthread__unpark_max = PTHREAD__UNPARK_MAX; |
100 | int pthread__dbg; /* set by libpthread_dbg if active */ | | 100 | int pthread__dbg; /* set by libpthread_dbg if active */ |
101 | | | 101 | |
102 | /* | | 102 | /* |
103 | * We have to initialize the pthread_stack* variables here because | | 103 | * We have to initialize the pthread_stack* variables here because |
104 | * mutexes are used before pthread_init() and thus pthread__initmain() | | 104 | * mutexes are used before pthread_init() and thus pthread__initmain() |
105 | * are called. Since mutexes only save the stack pointer and not a | | 105 | * are called. Since mutexes only save the stack pointer and not a |
106 | * pointer to the thread data, it is safe to change the mapping from | | 106 | * pointer to the thread data, it is safe to change the mapping from |
107 | * stack pointer to thread data afterwards. | | 107 | * stack pointer to thread data afterwards. |
108 | */ | | 108 | */ |
109 | size_t pthread__stacksize; | | 109 | size_t pthread__stacksize; |
110 | size_t pthread__pagesize; | | 110 | size_t pthread__pagesize; |
111 | static struct __pthread_st pthread__main; | | 111 | static struct __pthread_st pthread__main; |
112 | | | 112 | |
113 | int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); | | 113 | int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); |
114 | | | 114 | |
115 | __strong_alias(__libc_thr_self,pthread_self) | | 115 | __strong_alias(__libc_thr_self,pthread_self) |
116 | __strong_alias(__libc_thr_create,pthread_create) | | 116 | __strong_alias(__libc_thr_create,pthread_create) |
117 | __strong_alias(__libc_thr_exit,pthread_exit) | | 117 | __strong_alias(__libc_thr_exit,pthread_exit) |
118 | __strong_alias(__libc_thr_errno,pthread__errno) | | 118 | __strong_alias(__libc_thr_errno,pthread__errno) |
119 | __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate) | | 119 | __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate) |
120 | __strong_alias(__libc_thr_equal,pthread_equal) | | 120 | __strong_alias(__libc_thr_equal,pthread_equal) |
121 | __strong_alias(__libc_thr_init,pthread__init) | | 121 | __strong_alias(__libc_thr_init,pthread__init) |
122 | | | 122 | |
123 | /* | | 123 | /* |
124 | * Static library kludge. Place a reference to a symbol any library | | 124 | * Static library kludge. Place a reference to a symbol any library |
125 | * file which does not already have a reference here. | | 125 | * file which does not already have a reference here. |
126 | */ | | 126 | */ |
127 | extern int pthread__cancel_stub_binder; | | 127 | extern int pthread__cancel_stub_binder; |
128 | | | 128 | |
129 | void *pthread__static_lib_binder[] = { | | 129 | void *pthread__static_lib_binder[] = { |
130 | &pthread__cancel_stub_binder, | | 130 | &pthread__cancel_stub_binder, |
131 | pthread_cond_init, | | 131 | pthread_cond_init, |
132 | pthread_mutex_init, | | 132 | pthread_mutex_init, |
133 | pthread_rwlock_init, | | 133 | pthread_rwlock_init, |
134 | pthread_barrier_init, | | 134 | pthread_barrier_init, |
135 | pthread_key_create, | | 135 | pthread_key_create, |
136 | pthread_setspecific, | | 136 | pthread_setspecific, |
137 | }; | | 137 | }; |
138 | | | 138 | |
139 | #define NHASHLOCK 64 | | 139 | #define NHASHLOCK 64 |
140 | | | 140 | |
141 | static union hashlock { | | 141 | static union hashlock { |
142 | pthread_mutex_t mutex; | | 142 | pthread_mutex_t mutex; |
143 | char pad[64]; | | 143 | char pad[64]; |
144 | } hashlocks[NHASHLOCK] __aligned(64); | | 144 | } hashlocks[NHASHLOCK] __aligned(64); |
145 | | | 145 | |
146 | /* | | 146 | /* |
147 | * This needs to be started by the library loading code, before main() | | 147 | * This needs to be started by the library loading code, before main() |
148 | * gets to run, for various things that use the state of the initial thread | | 148 | * gets to run, for various things that use the state of the initial thread |
149 | * to work properly (thread-specific data is an application-visible example; | | 149 | * to work properly (thread-specific data is an application-visible example; |
150 | * spinlock counts for mutexes is an internal example). | | 150 | * spinlock counts for mutexes is an internal example). |
151 | */ | | 151 | */ |
152 | void | | 152 | void |
153 | pthread__init(void) | | 153 | pthread__init(void) |
154 | { | | 154 | { |
155 | pthread_t first; | | 155 | pthread_t first; |
156 | char *p; | | 156 | char *p; |
157 | int i, mib[2]; | | 157 | int i, mib[2]; |
158 | size_t len; | | 158 | size_t len; |
159 | extern int __isthreaded; | | 159 | extern int __isthreaded; |
160 | | | 160 | |
161 | pthread__pagesize = (size_t)sysconf(_SC_PAGESIZE); | | 161 | pthread__pagesize = (size_t)sysconf(_SC_PAGESIZE); |
162 | | | 162 | |
163 | mib[0] = CTL_HW; | | 163 | mib[0] = CTL_HW; |
164 | mib[1] = HW_NCPU; | | 164 | mib[1] = HW_NCPU; |
165 | | | 165 | |
166 | len = sizeof(pthread__concurrency); | | 166 | len = sizeof(pthread__concurrency); |
167 | if (sysctl(mib, 2, &pthread__concurrency, &len, NULL, 0) == -1) | | 167 | if (sysctl(mib, 2, &pthread__concurrency, &len, NULL, 0) == -1) |
168 | err(1, "sysctl(hw.ncpu"); | | 168 | err(1, "sysctl(hw.ncpu"); |
169 | | | 169 | |
170 | mib[0] = CTL_KERN; | | 170 | mib[0] = CTL_KERN; |
171 | mib[1] = KERN_OSREV; | | 171 | mib[1] = KERN_OSREV; |
172 | | | 172 | |
173 | /* Initialize locks first; they're needed elsewhere. */ | | 173 | /* Initialize locks first; they're needed elsewhere. */ |
174 | pthread__lockprim_init(); | | 174 | pthread__lockprim_init(); |
175 | for (i = 0; i < NHASHLOCK; i++) { | | 175 | for (i = 0; i < NHASHLOCK; i++) { |
176 | pthread_mutex_init(&hashlocks[i].mutex, NULL); | | 176 | pthread_mutex_init(&hashlocks[i].mutex, NULL); |
177 | } | | 177 | } |
178 | | | 178 | |
179 | /* Fetch parameters. */ | | 179 | /* Fetch parameters. */ |
180 | i = (int)_lwp_unpark_all(NULL, 0, NULL); | | 180 | i = (int)_lwp_unpark_all(NULL, 0, NULL); |
181 | if (i == -1) | | 181 | if (i == -1) |
182 | err(1, "_lwp_unpark_all"); | | 182 | err(1, "_lwp_unpark_all"); |
183 | if (i < pthread__unpark_max) | | 183 | if (i < pthread__unpark_max) |
184 | pthread__unpark_max = i; | | 184 | pthread__unpark_max = i; |
185 | | | 185 | |
186 | /* Basic data structure setup */ | | 186 | /* Basic data structure setup */ |
187 | pthread_attr_init(&pthread_default_attr); | | 187 | pthread_attr_init(&pthread_default_attr); |
188 | PTQ_INIT(&pthread__allqueue); | | 188 | PTQ_INIT(&pthread__allqueue); |
189 | PTQ_INIT(&pthread__deadqueue); | | 189 | PTQ_INIT(&pthread__deadqueue); |
190 | RB_INIT(&pthread__alltree); | | 190 | RB_INIT(&pthread__alltree); |
191 | | | 191 | |
192 | /* Create the thread structure corresponding to main() */ | | 192 | /* Create the thread structure corresponding to main() */ |
193 | pthread__initmain(&first); | | 193 | pthread__initmain(&first); |
194 | pthread__initthread(first); | | 194 | pthread__initthread(first); |
195 | pthread__scrubthread(first, NULL, 0); | | 195 | pthread__scrubthread(first, NULL, 0); |
196 | | | 196 | |
197 | first->pt_lid = _lwp_self(); | | 197 | first->pt_lid = _lwp_self(); |
198 | PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq); | | 198 | PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq); |
199 | RB_INSERT(__pthread__alltree, &pthread__alltree, first); | | 199 | RB_INSERT(__pthread__alltree, &pthread__alltree, first); |
200 | | | 200 | |
201 | if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &first->pt_lwpctl) != 0) { | | 201 | if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &first->pt_lwpctl) != 0) { |
202 | err(1, "_lwp_ctl"); | | 202 | err(1, "_lwp_ctl"); |
203 | } | | 203 | } |
204 | | | 204 | |
205 | /* Start subsystems */ | | 205 | /* Start subsystems */ |
206 | PTHREAD_MD_INIT | | 206 | PTHREAD_MD_INIT |
207 | | | 207 | |
208 | for (p = pthread__getenv("PTHREAD_DIAGASSERT"); p && *p; p++) { | | 208 | for (p = pthread__getenv("PTHREAD_DIAGASSERT"); p && *p; p++) { |
209 | switch (*p) { | | 209 | switch (*p) { |
210 | case 'a': | | 210 | case 'a': |
211 | pthread__diagassert |= DIAGASSERT_ABORT; | | 211 | pthread__diagassert |= DIAGASSERT_ABORT; |
212 | break; | | 212 | break; |
213 | case 'A': | | 213 | case 'A': |
214 | pthread__diagassert &= ~DIAGASSERT_ABORT; | | 214 | pthread__diagassert &= ~DIAGASSERT_ABORT; |
215 | break; | | 215 | break; |
216 | case 'e': | | 216 | case 'e': |
217 | pthread__diagassert |= DIAGASSERT_STDERR; | | 217 | pthread__diagassert |= DIAGASSERT_STDERR; |
218 | break; | | 218 | break; |
219 | case 'E': | | 219 | case 'E': |
220 | pthread__diagassert &= ~DIAGASSERT_STDERR; | | 220 | pthread__diagassert &= ~DIAGASSERT_STDERR; |
221 | break; | | 221 | break; |
222 | case 'l': | | 222 | case 'l': |
223 | pthread__diagassert |= DIAGASSERT_SYSLOG; | | 223 | pthread__diagassert |= DIAGASSERT_SYSLOG; |
224 | break; | | 224 | break; |
225 | case 'L': | | 225 | case 'L': |
226 | pthread__diagassert &= ~DIAGASSERT_SYSLOG; | | 226 | pthread__diagassert &= ~DIAGASSERT_SYSLOG; |
227 | break; | | 227 | break; |
228 | } | | 228 | } |
229 | } | | 229 | } |
230 | | | 230 | |
231 | /* Tell libc that we're here and it should role-play accordingly. */ | | 231 | /* Tell libc that we're here and it should role-play accordingly. */ |
232 | pthread__first = first; | | 232 | pthread__first = first; |
233 | pthread_atfork(NULL, NULL, pthread__fork_callback); | | 233 | pthread_atfork(NULL, NULL, pthread__fork_callback); |
234 | __isthreaded = 1; | | 234 | __isthreaded = 1; |
235 | } | | 235 | } |
236 | | | 236 | |
237 | static void | | 237 | static void |
238 | pthread__fork_callback(void) | | 238 | pthread__fork_callback(void) |
239 | { | | 239 | { |
240 | struct __pthread_st *self; | | 240 | struct __pthread_st *self; |
241 | | | 241 | |
242 | /* lwpctl state is not copied across fork. */ | | 242 | /* lwpctl state is not copied across fork. */ |
243 | if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &pthread__first->pt_lwpctl)) { | | 243 | if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &pthread__first->pt_lwpctl)) { |
244 | err(1, "_lwp_ctl"); | | 244 | err(1, "_lwp_ctl"); |
245 | } | | 245 | } |
246 | self = pthread__self(); | | 246 | self = pthread__self(); |
247 | self->pt_lid = _lwp_self(); | | 247 | self->pt_lid = _lwp_self(); |
248 | } | | 248 | } |
249 | | | 249 | |
250 | static void | | 250 | static void |
251 | pthread__child_callback(void) | | 251 | pthread__child_callback(void) |
252 | { | | 252 | { |
253 | | | 253 | |
254 | /* | | 254 | /* |
255 | * Clean up data structures that a forked child process might | | 255 | * Clean up data structures that a forked child process might |
256 | * trip over. Note that if threads have been created (causing | | 256 | * trip over. Note that if threads have been created (causing |
257 | * this handler to be registered) the standards say that the | | 257 | * this handler to be registered) the standards say that the |
258 | * child will trigger undefined behavior if it makes any | | 258 | * child will trigger undefined behavior if it makes any |
259 | * pthread_* calls (or any other calls that aren't | | 259 | * pthread_* calls (or any other calls that aren't |
260 | * async-signal-safe), so we don't really have to clean up | | 260 | * async-signal-safe), so we don't really have to clean up |
261 | * much. Anything that permits some pthread_* calls to work is | | 261 | * much. Anything that permits some pthread_* calls to work is |
262 | * merely being polite. | | 262 | * merely being polite. |
263 | */ | | 263 | */ |
264 | pthread__started = 0; | | 264 | pthread__started = 0; |
265 | } | | 265 | } |
266 | | | 266 | |
267 | static void | | 267 | static void |
268 | pthread__start(void) | | 268 | pthread__start(void) |
269 | { | | 269 | { |
270 | | | 270 | |
271 | /* | | 271 | /* |
272 | * Per-process timers are cleared by fork(); despite the | | 272 | * Per-process timers are cleared by fork(); despite the |
273 | * various restrictions on fork() and threads, it's legal to | | 273 | * various restrictions on fork() and threads, it's legal to |
274 | * fork() before creating any threads. | | 274 | * fork() before creating any threads. |
275 | */ | | 275 | */ |
276 | pthread_atfork(NULL, NULL, pthread__child_callback); | | 276 | pthread_atfork(NULL, NULL, pthread__child_callback); |
277 | } | | 277 | } |
278 | | | 278 | |
279 | | | 279 | |
280 | /* General-purpose thread data structure sanitization. */ | | 280 | /* General-purpose thread data structure sanitization. */ |
281 | /* ARGSUSED */ | | 281 | /* ARGSUSED */ |
282 | static void | | 282 | static void |
283 | pthread__initthread(pthread_t t) | | 283 | pthread__initthread(pthread_t t) |
284 | { | | 284 | { |
285 | | | 285 | |
286 | t->pt_self = t; | | 286 | t->pt_self = t; |
287 | t->pt_magic = PT_MAGIC; | | 287 | t->pt_magic = PT_MAGIC; |
288 | t->pt_willpark = 0; | | 288 | t->pt_willpark = 0; |
289 | t->pt_unpark = 0; | | 289 | t->pt_unpark = 0; |
290 | t->pt_nwaiters = 0; | | 290 | t->pt_nwaiters = 0; |
291 | t->pt_sleepobj = NULL; | | 291 | t->pt_sleepobj = NULL; |
292 | t->pt_signalled = 0; | | 292 | t->pt_signalled = 0; |
293 | t->pt_havespecific = 0; | | 293 | t->pt_havespecific = 0; |
294 | t->pt_early = NULL; | | 294 | t->pt_early = NULL; |
295 | t->pt_lwpctl = &pthread__dummy_lwpctl; | | 295 | t->pt_lwpctl = &pthread__dummy_lwpctl; |
296 | t->pt_blocking = 0; | | 296 | t->pt_blocking = 0; |
297 | t->pt_droplock = NULL; | | 297 | t->pt_droplock = NULL; |
298 | | | 298 | |
299 | memcpy(&t->pt_lockops, pthread__lock_ops, sizeof(t->pt_lockops)); | | 299 | memcpy(&t->pt_lockops, pthread__lock_ops, sizeof(t->pt_lockops)); |
300 | pthread_mutex_init(&t->pt_lock, NULL); | | 300 | pthread_mutex_init(&t->pt_lock, NULL); |
301 | PTQ_INIT(&t->pt_cleanup_stack); | | 301 | PTQ_INIT(&t->pt_cleanup_stack); |
302 | pthread_cond_init(&t->pt_joiners, NULL); | | 302 | pthread_cond_init(&t->pt_joiners, NULL); |
303 | memset(&t->pt_specific, 0, sizeof(t->pt_specific)); | | 303 | memset(&t->pt_specific, 0, sizeof(t->pt_specific)); |
304 | } | | 304 | } |
305 | | | 305 | |
306 | static void | | 306 | static void |
307 | pthread__scrubthread(pthread_t t, char *name, int flags) | | 307 | pthread__scrubthread(pthread_t t, char *name, int flags) |
308 | { | | 308 | { |
309 | | | 309 | |
310 | t->pt_state = PT_STATE_RUNNING; | | 310 | t->pt_state = PT_STATE_RUNNING; |
311 | t->pt_exitval = NULL; | | 311 | t->pt_exitval = NULL; |
312 | t->pt_flags = flags; | | 312 | t->pt_flags = flags; |
313 | t->pt_cancel = 0; | | 313 | t->pt_cancel = 0; |
314 | t->pt_errno = 0; | | 314 | t->pt_errno = 0; |
315 | t->pt_name = name; | | 315 | t->pt_name = name; |
316 | t->pt_lid = 0; | | 316 | t->pt_lid = 0; |
317 | } | | 317 | } |
318 | | | 318 | |
319 | static int | | 319 | static int |
320 | pthread__newstack(pthread_t newthread) | | 320 | pthread__newstack(pthread_t newthread) |
321 | { | | 321 | { |
322 | void *stackbase, *redzone; | | 322 | void *stackbase, *redzone; |
323 | | | 323 | |
324 | stackbase = mmap(NULL, pthread__stacksize, | | 324 | stackbase = mmap(NULL, pthread__stacksize, |
325 | PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, (off_t)0); | | 325 | PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, (off_t)0); |
326 | if (stackbase == MAP_FAILED) | | 326 | if (stackbase == MAP_FAILED) |
327 | return ENOMEM; | | 327 | return ENOMEM; |
328 | newthread->pt_stack.ss_size = pthread__stacksize - pthread__pagesize; | | 328 | newthread->pt_stack.ss_size = pthread__stacksize - pthread__pagesize; |
329 | newthread->pt_stack.ss_sp = stackbase; | | 329 | newthread->pt_stack.ss_sp = stackbase; |
330 | #ifdef __MACHINE_STACK_GROWS_UP | | 330 | #ifdef __MACHINE_STACK_GROWS_UP |
331 | redzone = (char *)stackbase + newthread->pt_stack.ss_size; | | 331 | redzone = (char *)stackbase + newthread->pt_stack.ss_size; |
332 | #else | | 332 | #else |
333 | redzone = (char *)stackbase; | | 333 | redzone = (char *)stackbase; |
334 | #endif | | 334 | #endif |
335 | if (mprotect(redzone, pthread__pagesize, PROT_NONE) == -1) { | | 335 | if (mprotect(redzone, pthread__pagesize, PROT_NONE) == -1) { |
336 | munmap(stackbase, pthread__stacksize); | | 336 | munmap(stackbase, pthread__stacksize); |
337 | return EPERM; | | 337 | return EPERM; |
338 | } | | 338 | } |
339 | return 0; | | 339 | return 0; |
340 | } | | 340 | } |
341 | | | 341 | |
342 | int | | 342 | int |
343 | pthread_create(pthread_t *thread, const pthread_attr_t *attr, | | 343 | pthread_create(pthread_t *thread, const pthread_attr_t *attr, |
344 | void *(*startfunc)(void *), void *arg) | | 344 | void *(*startfunc)(void *), void *arg) |
345 | { | | 345 | { |
346 | pthread_t newthread; | | 346 | pthread_t newthread; |
347 | pthread_attr_t nattr; | | 347 | pthread_attr_t nattr; |
348 | struct pthread_attr_private *p; | | 348 | struct pthread_attr_private *p; |
349 | char * volatile name; | | 349 | char * volatile name; |
350 | unsigned long flag; | | 350 | unsigned long flag; |
351 | void *private_area; | | 351 | void *private_area; |
352 | int ret; | | 352 | int ret; |
353 | | | 353 | |
354 | /* | | 354 | /* |
355 | * It's okay to check this without a lock because there can | | 355 | * It's okay to check this without a lock because there can |
356 | * only be one thread before it becomes true. | | 356 | * only be one thread before it becomes true. |
357 | */ | | 357 | */ |
358 | if (pthread__started == 0) { | | 358 | if (pthread__started == 0) { |
359 | pthread__start(); | | 359 | pthread__start(); |
360 | pthread__started = 1; | | 360 | pthread__started = 1; |
361 | } | | 361 | } |
362 | | | 362 | |
363 | if (attr == NULL) | | 363 | if (attr == NULL) |
364 | nattr = pthread_default_attr; | | 364 | nattr = pthread_default_attr; |
365 | else if (attr->pta_magic == PT_ATTR_MAGIC) | | 365 | else if (attr->pta_magic == PT_ATTR_MAGIC) |
366 | nattr = *attr; | | 366 | nattr = *attr; |
367 | else | | 367 | else |
368 | return EINVAL; | | 368 | return EINVAL; |
369 | | | 369 | |
370 | /* Fetch misc. attributes from the attr structure. */ | | 370 | /* Fetch misc. attributes from the attr structure. */ |
371 | name = NULL; | | 371 | name = NULL; |
372 | if ((p = nattr.pta_private) != NULL) | | 372 | if ((p = nattr.pta_private) != NULL) |
373 | if (p->ptap_name[0] != '\0') | | 373 | if (p->ptap_name[0] != '\0') |
374 | if ((name = strdup(p->ptap_name)) == NULL) | | 374 | if ((name = strdup(p->ptap_name)) == NULL) |
375 | return ENOMEM; | | 375 | return ENOMEM; |
376 | | | 376 | |
377 | newthread = NULL; | | 377 | newthread = NULL; |
378 | | | 378 | |
379 | /* | | 379 | /* |
380 | * Try to reclaim a dead thread. | | 380 | * Try to reclaim a dead thread. |
381 | */ | | 381 | */ |
382 | if (!PTQ_EMPTY(&pthread__deadqueue)) { | | 382 | if (!PTQ_EMPTY(&pthread__deadqueue)) { |
383 | pthread_mutex_lock(&pthread__deadqueue_lock); | | 383 | pthread_mutex_lock(&pthread__deadqueue_lock); |
384 | PTQ_FOREACH(newthread, &pthread__deadqueue, pt_deadq) { | | 384 | PTQ_FOREACH(newthread, &pthread__deadqueue, pt_deadq) { |
385 | /* Still running? */ | | 385 | /* Still running? */ |
386 | if (newthread->pt_lwpctl->lc_curcpu == | | 386 | if (newthread->pt_lwpctl->lc_curcpu == |
387 | LWPCTL_CPU_EXITED || | | 387 | LWPCTL_CPU_EXITED || |
388 | (_lwp_kill(newthread->pt_lid, 0) == -1 && | | 388 | (_lwp_kill(newthread->pt_lid, 0) == -1 && |
389 | errno == ESRCH)) | | 389 | errno == ESRCH)) |
390 | break; | | 390 | break; |
391 | } | | 391 | } |
392 | if (newthread) | | 392 | if (newthread) |
393 | PTQ_REMOVE(&pthread__deadqueue, newthread, pt_deadq); | | 393 | PTQ_REMOVE(&pthread__deadqueue, newthread, pt_deadq); |
394 | pthread_mutex_unlock(&pthread__deadqueue_lock); | | 394 | pthread_mutex_unlock(&pthread__deadqueue_lock); |
395 | #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) | | 395 | #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) |
396 | if (newthread && newthread->pt_tls) { | | 396 | if (newthread && newthread->pt_tls) { |
397 | _rtld_tls_free(newthread->pt_tls); | | 397 | _rtld_tls_free(newthread->pt_tls); |
398 | newthread->pt_tls = NULL; | | 398 | newthread->pt_tls = NULL; |
399 | } | | 399 | } |
400 | #endif | | 400 | #endif |
401 | } | | 401 | } |
402 | | | 402 | |
403 | /* | | 403 | /* |
404 | * If necessary set up a stack, allocate space for a pthread_st, | | 404 | * If necessary set up a stack, allocate space for a pthread_st, |
405 | * and initialize it. | | 405 | * and initialize it. |
406 | */ | | 406 | */ |
407 | if (newthread == NULL) { | | 407 | if (newthread == NULL) { |
408 | newthread = malloc(sizeof(*newthread)); | | 408 | newthread = malloc(sizeof(*newthread)); |
409 | if (newthread == NULL) { | | 409 | if (newthread == NULL) { |
410 | free(name); | | 410 | free(name); |
411 | return ENOMEM; | | 411 | return ENOMEM; |
412 | } | | 412 | } |
413 | | | 413 | |
414 | if (pthread__newstack(newthread)) { | | 414 | if (pthread__newstack(newthread)) { |
415 | free(newthread); | | 415 | free(newthread); |
416 | free(name); | | 416 | free(name); |
417 | return ENOMEM; | | 417 | return ENOMEM; |
418 | } | | 418 | } |
419 | | | 419 | |
420 | /* This is used only when creating the thread. */ | | 420 | /* This is used only when creating the thread. */ |
421 | _INITCONTEXT_U(&newthread->pt_uc); | | 421 | _INITCONTEXT_U(&newthread->pt_uc); |
422 | newthread->pt_uc.uc_stack = newthread->pt_stack; | | 422 | newthread->pt_uc.uc_stack = newthread->pt_stack; |
423 | newthread->pt_uc.uc_link = NULL; | | 423 | newthread->pt_uc.uc_link = NULL; |
424 | #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) | | 424 | #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) |
425 | newthread->pt_tls = NULL; | | 425 | newthread->pt_tls = NULL; |
426 | #endif | | 426 | #endif |
427 | | | 427 | |
428 | /* Add to list of all threads. */ | | 428 | /* Add to list of all threads. */ |
429 | pthread_rwlock_wrlock(&pthread__alltree_lock); | | 429 | pthread_rwlock_wrlock(&pthread__alltree_lock); |
430 | PTQ_INSERT_TAIL(&pthread__allqueue, newthread, pt_allq); | | 430 | PTQ_INSERT_TAIL(&pthread__allqueue, newthread, pt_allq); |
431 | RB_INSERT(__pthread__alltree, &pthread__alltree, newthread); | | 431 | RB_INSERT(__pthread__alltree, &pthread__alltree, newthread); |
432 | pthread_rwlock_unlock(&pthread__alltree_lock); | | 432 | pthread_rwlock_unlock(&pthread__alltree_lock); |
433 | | | 433 | |
434 | /* Will be reset by the thread upon exit. */ | | 434 | /* Will be reset by the thread upon exit. */ |
435 | pthread__initthread(newthread); | | 435 | pthread__initthread(newthread); |
436 | } | | 436 | } |
437 | | | 437 | |
438 | /* | | 438 | /* |
439 | * Create the new LWP. | | 439 | * Create the new LWP. |
440 | */ | | 440 | */ |
441 | pthread__scrubthread(newthread, name, nattr.pta_flags); | | 441 | pthread__scrubthread(newthread, name, nattr.pta_flags); |
442 | newthread->pt_func = startfunc; | | 442 | newthread->pt_func = startfunc; |
443 | newthread->pt_arg = arg; | | 443 | newthread->pt_arg = arg; |
444 | #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) | | 444 | #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) |
445 | private_area = newthread->pt_tls = _rtld_tls_allocate(); | | 445 | private_area = newthread->pt_tls = _rtld_tls_allocate(); |
446 | newthread->pt_tls->tcb_pthread = newthread; | | 446 | newthread->pt_tls->tcb_pthread = newthread; |
447 | #else | | 447 | #else |
448 | private_area = newthread; | | 448 | private_area = newthread; |
449 | #endif | | 449 | #endif |
450 | | | 450 | |
451 | _lwp_makecontext(&newthread->pt_uc, pthread__create_tramp, | | 451 | _lwp_makecontext(&newthread->pt_uc, pthread__create_tramp, |
452 | newthread, private_area, newthread->pt_stack.ss_sp, | | 452 | newthread, private_area, newthread->pt_stack.ss_sp, |
453 | newthread->pt_stack.ss_size); | | 453 | newthread->pt_stack.ss_size); |
454 | | | 454 | |
455 | flag = LWP_DETACHED; | | 455 | flag = LWP_DETACHED; |
456 | if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0 || | | 456 | if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0 || |
457 | (nattr.pta_flags & PT_FLAG_EXPLICIT_SCHED) != 0) | | 457 | (nattr.pta_flags & PT_FLAG_EXPLICIT_SCHED) != 0) |
458 | flag |= LWP_SUSPENDED; | | 458 | flag |= LWP_SUSPENDED; |
459 | ret = _lwp_create(&newthread->pt_uc, flag, &newthread->pt_lid); | | 459 | ret = _lwp_create(&newthread->pt_uc, flag, &newthread->pt_lid); |
460 | if (ret != 0) { | | 460 | if (ret != 0) { |
461 | pthread_mutex_lock(&newthread->pt_lock); | | 461 | pthread_mutex_lock(&newthread->pt_lock); |
462 | /* Will unlock and free name. */ | | 462 | /* Will unlock and free name. */ |
463 | pthread__reap(newthread); | | 463 | pthread__reap(newthread); |
464 | return ret; | | 464 | return ret; |
465 | } | | 465 | } |
466 | | | 466 | |
467 | if ((nattr.pta_flags & PT_FLAG_EXPLICIT_SCHED) != 0) { | | 467 | if ((nattr.pta_flags & PT_FLAG_EXPLICIT_SCHED) != 0) { |
468 | if (p != NULL) { | | 468 | if (p != NULL) { |
469 | (void)pthread_setschedparam(newthread, p->ptap_policy, | | 469 | (void)pthread_setschedparam(newthread, p->ptap_policy, |
470 | &p->ptap_sp); | | 470 | &p->ptap_sp); |
471 | } | | 471 | } |
472 | if ((newthread->pt_flags & PT_FLAG_SUSPENDED) == 0) { | | 472 | if ((newthread->pt_flags & PT_FLAG_SUSPENDED) == 0) { |
473 | (void)_lwp_continue(newthread->pt_lid); | | 473 | (void)_lwp_continue(newthread->pt_lid); |
474 | } | | 474 | } |
475 | } | | 475 | } |
476 | | | 476 | |
477 | *thread = newthread; | | 477 | *thread = newthread; |
478 | | | 478 | |
479 | return 0; | | 479 | return 0; |
480 | } | | 480 | } |
481 | | | 481 | |
482 | | | 482 | |
483 | __dead static void | | 483 | __dead static void |
484 | pthread__create_tramp(void *cookie) | | 484 | pthread__create_tramp(void *cookie) |
485 | { | | 485 | { |
486 | pthread_t self; | | 486 | pthread_t self; |
487 | void *retval; | | 487 | void *retval; |
488 | | | 488 | |
489 | self = cookie; | | 489 | self = cookie; |
490 | | | 490 | |
491 | /* | | 491 | /* |
492 | * Throw away some stack in a feeble attempt to reduce cache | | 492 | * Throw away some stack in a feeble attempt to reduce cache |
493 | * thrash. May help for SMT processors. XXX We should not | | 493 | * thrash. May help for SMT processors. XXX We should not |
494 | * be allocating stacks on fixed 2MB boundaries. Needs a | | 494 | * be allocating stacks on fixed 2MB boundaries. Needs a |
495 | * thread register or decent thread local storage. | | 495 | * thread register or decent thread local storage. |
496 | * | | 496 | * |
497 | * Note that we may race with the kernel in _lwp_create(), | | 497 | * Note that we may race with the kernel in _lwp_create(), |
498 | * and so pt_lid can be unset at this point, but we don't | | 498 | * and so pt_lid can be unset at this point, but we don't |
499 | * care. | | 499 | * care. |
500 | */ | | 500 | */ |
501 | (void)alloca(((unsigned)self->pt_lid & 7) << 8); | | 501 | (void)alloca(((unsigned)self->pt_lid & 7) << 8); |
502 | | | 502 | |
503 | if (self->pt_name != NULL) { | | 503 | if (self->pt_name != NULL) { |
504 | pthread_mutex_lock(&self->pt_lock); | | 504 | pthread_mutex_lock(&self->pt_lock); |
505 | if (self->pt_name != NULL) | | 505 | if (self->pt_name != NULL) |
506 | (void)_lwp_setname(0, self->pt_name); | | 506 | (void)_lwp_setname(0, self->pt_name); |
507 | pthread_mutex_unlock(&self->pt_lock); | | 507 | pthread_mutex_unlock(&self->pt_lock); |
508 | } | | 508 | } |
509 | | | 509 | |
510 | if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) { | | 510 | if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) { |
511 | err(1, "_lwp_ctl"); | | 511 | err(1, "_lwp_ctl"); |
512 | } | | 512 | } |
513 | | | 513 | |
514 | retval = (*self->pt_func)(self->pt_arg); | | 514 | retval = (*self->pt_func)(self->pt_arg); |
515 | | | 515 | |
516 | pthread_exit(retval); | | 516 | pthread_exit(retval); |
517 | | | 517 | |
518 | /*NOTREACHED*/ | | 518 | /*NOTREACHED*/ |
519 | pthread__abort(); | | 519 | pthread__abort(); |
520 | } | | 520 | } |
521 | | | 521 | |
522 | int | | 522 | int |
523 | pthread_suspend_np(pthread_t thread) | | 523 | pthread_suspend_np(pthread_t thread) |
524 | { | | 524 | { |
525 | pthread_t self; | | 525 | pthread_t self; |
526 | | | 526 | |
527 | self = pthread__self(); | | 527 | self = pthread__self(); |
528 | if (self == thread) { | | 528 | if (self == thread) { |
529 | return EDEADLK; | | 529 | return EDEADLK; |
530 | } | | 530 | } |
531 | if (pthread__find(thread) != 0) | | 531 | if (pthread__find(thread) != 0) |
532 | return ESRCH; | | 532 | return ESRCH; |
533 | if (_lwp_suspend(thread->pt_lid) == 0) | | 533 | if (_lwp_suspend(thread->pt_lid) == 0) |
534 | return 0; | | 534 | return 0; |
535 | return errno; | | 535 | return errno; |
536 | } | | 536 | } |
537 | | | 537 | |
538 | int | | 538 | int |
539 | pthread_resume_np(pthread_t thread) | | 539 | pthread_resume_np(pthread_t thread) |
540 | { | | 540 | { |
541 | | | 541 | |
542 | if (pthread__find(thread) != 0) | | 542 | if (pthread__find(thread) != 0) |
543 | return ESRCH; | | 543 | return ESRCH; |
544 | if (_lwp_continue(thread->pt_lid) == 0) | | 544 | if (_lwp_continue(thread->pt_lid) == 0) |
545 | return 0; | | 545 | return 0; |
546 | return errno; | | 546 | return errno; |
547 | } | | 547 | } |
548 | | | 548 | |
549 | void | | 549 | void |
550 | pthread_exit(void *retval) | | 550 | pthread_exit(void *retval) |
551 | { | | 551 | { |
552 | pthread_t self; | | 552 | pthread_t self; |
553 | struct pt_clean_t *cleanup; | | 553 | struct pt_clean_t *cleanup; |
554 | char *name; | | 554 | char *name; |
555 | | | 555 | |
556 | self = pthread__self(); | | 556 | self = pthread__self(); |
557 | | | 557 | |
558 | /* Disable cancellability. */ | | 558 | /* Disable cancellability. */ |
559 | pthread_mutex_lock(&self->pt_lock); | | 559 | pthread_mutex_lock(&self->pt_lock); |
560 | self->pt_flags |= PT_FLAG_CS_DISABLED; | | 560 | self->pt_flags |= PT_FLAG_CS_DISABLED; |
561 | self->pt_cancel = 0; | | 561 | self->pt_cancel = 0; |
562 | | | 562 | |
563 | /* Call any cancellation cleanup handlers */ | | 563 | /* Call any cancellation cleanup handlers */ |
564 | if (!PTQ_EMPTY(&self->pt_cleanup_stack)) { | | 564 | if (!PTQ_EMPTY(&self->pt_cleanup_stack)) { |
565 | pthread_mutex_unlock(&self->pt_lock); | | 565 | pthread_mutex_unlock(&self->pt_lock); |
566 | while (!PTQ_EMPTY(&self->pt_cleanup_stack)) { | | 566 | while (!PTQ_EMPTY(&self->pt_cleanup_stack)) { |
567 | cleanup = PTQ_FIRST(&self->pt_cleanup_stack); | | 567 | cleanup = PTQ_FIRST(&self->pt_cleanup_stack); |
568 | PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next); | | 568 | PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next); |
569 | (*cleanup->ptc_cleanup)(cleanup->ptc_arg); | | 569 | (*cleanup->ptc_cleanup)(cleanup->ptc_arg); |
570 | } | | 570 | } |
571 | pthread_mutex_lock(&self->pt_lock); | | 571 | pthread_mutex_lock(&self->pt_lock); |
572 | } | | 572 | } |
573 | | | 573 | |
574 | /* Perform cleanup of thread-specific data */ | | 574 | /* Perform cleanup of thread-specific data */ |
575 | pthread__destroy_tsd(self); | | 575 | pthread__destroy_tsd(self); |
576 | | | 576 | |
577 | /* Signal our exit. */ | | 577 | /* Signal our exit. */ |
578 | self->pt_exitval = retval; | | 578 | self->pt_exitval = retval; |
579 | if (self->pt_flags & PT_FLAG_DETACHED) { | | 579 | if (self->pt_flags & PT_FLAG_DETACHED) { |
580 | self->pt_state = PT_STATE_DEAD; | | 580 | self->pt_state = PT_STATE_DEAD; |
581 | name = self->pt_name; | | 581 | name = self->pt_name; |
582 | self->pt_name = NULL; | | 582 | self->pt_name = NULL; |
583 | pthread_mutex_unlock(&self->pt_lock); | | 583 | pthread_mutex_unlock(&self->pt_lock); |
584 | if (name != NULL) | | 584 | if (name != NULL) |
585 | free(name); | | 585 | free(name); |
586 | pthread_mutex_lock(&pthread__deadqueue_lock); | | 586 | pthread_mutex_lock(&pthread__deadqueue_lock); |
587 | PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_deadq); | | 587 | PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_deadq); |
588 | pthread_mutex_unlock(&pthread__deadqueue_lock); | | 588 | pthread_mutex_unlock(&pthread__deadqueue_lock); |
589 | _lwp_exit(); | | 589 | _lwp_exit(); |
590 | } else { | | 590 | } else { |
591 | self->pt_state = PT_STATE_ZOMBIE; | | 591 | self->pt_state = PT_STATE_ZOMBIE; |
592 | pthread_cond_broadcast(&self->pt_joiners); | | 592 | pthread_cond_broadcast(&self->pt_joiners); |
593 | pthread_mutex_unlock(&self->pt_lock); | | 593 | pthread_mutex_unlock(&self->pt_lock); |
594 | /* Note: name will be freed by the joiner. */ | | 594 | /* Note: name will be freed by the joiner. */ |
595 | _lwp_exit(); | | 595 | _lwp_exit(); |
596 | } | | 596 | } |
597 | | | 597 | |
598 | /*NOTREACHED*/ | | 598 | /*NOTREACHED*/ |
599 | pthread__abort(); | | 599 | pthread__abort(); |
600 | exit(1); | | 600 | exit(1); |
601 | } | | 601 | } |
602 | | | 602 | |
603 | | | 603 | |
604 | int | | 604 | int |
605 | pthread_join(pthread_t thread, void **valptr) | | 605 | pthread_join(pthread_t thread, void **valptr) |
606 | { | | 606 | { |
607 | pthread_t self; | | 607 | pthread_t self; |
608 | int error; | | 608 | int error; |
609 | | | 609 | |
610 | self = pthread__self(); | | 610 | self = pthread__self(); |
611 | | | 611 | |
612 | if (pthread__find(thread) != 0) | | 612 | if (pthread__find(thread) != 0) |
613 | return ESRCH; | | 613 | return ESRCH; |
614 | | | 614 | |
615 | if (thread->pt_magic != PT_MAGIC) | | 615 | if (thread->pt_magic != PT_MAGIC) |
616 | return EINVAL; | | 616 | return EINVAL; |
617 | | | 617 | |
618 | if (thread == self) | | 618 | if (thread == self) |
619 | return EDEADLK; | | 619 | return EDEADLK; |
620 | | | 620 | |
621 | self->pt_droplock = &thread->pt_lock; | | 621 | self->pt_droplock = &thread->pt_lock; |
622 | pthread_mutex_lock(&thread->pt_lock); | | 622 | pthread_mutex_lock(&thread->pt_lock); |
623 | for (;;) { | | 623 | for (;;) { |
624 | if (thread->pt_state == PT_STATE_ZOMBIE) | | 624 | if (thread->pt_state == PT_STATE_ZOMBIE) |
625 | break; | | 625 | break; |
626 | if (thread->pt_state == PT_STATE_DEAD) { | | 626 | if (thread->pt_state == PT_STATE_DEAD) { |
627 | pthread_mutex_unlock(&thread->pt_lock); | | 627 | pthread_mutex_unlock(&thread->pt_lock); |
628 | self->pt_droplock = NULL; | | 628 | self->pt_droplock = NULL; |
629 | return ESRCH; | | 629 | return ESRCH; |
630 | } | | 630 | } |
631 | if ((thread->pt_flags & PT_FLAG_DETACHED) != 0) { | | 631 | if ((thread->pt_flags & PT_FLAG_DETACHED) != 0) { |
632 | pthread_mutex_unlock(&thread->pt_lock); | | 632 | pthread_mutex_unlock(&thread->pt_lock); |
633 | self->pt_droplock = NULL; | | 633 | self->pt_droplock = NULL; |
634 | return EINVAL; | | 634 | return EINVAL; |
635 | } | | 635 | } |
636 | error = pthread_cond_wait(&thread->pt_joiners, | | 636 | error = pthread_cond_wait(&thread->pt_joiners, |
637 | &thread->pt_lock); | | 637 | &thread->pt_lock); |
638 | if (error != 0) { | | 638 | if (error != 0) { |
639 | pthread__errorfunc(__FILE__, __LINE__, | | 639 | pthread__errorfunc(__FILE__, __LINE__, |
640 | __func__, "unexpected return from cond_wait()"); | | 640 | __func__, "unexpected return from cond_wait()"); |
641 | } | | 641 | } |
642 | | | 642 | |
643 | } | | 643 | } |
644 | pthread__testcancel(self); | | 644 | pthread__testcancel(self); |
645 | if (valptr != NULL) | | 645 | if (valptr != NULL) |
646 | *valptr = thread->pt_exitval; | | 646 | *valptr = thread->pt_exitval; |
647 | /* pthread__reap() will drop the lock. */ | | 647 | /* pthread__reap() will drop the lock. */ |
648 | pthread__reap(thread); | | 648 | pthread__reap(thread); |
649 | self->pt_droplock = NULL; | | 649 | self->pt_droplock = NULL; |
650 | | | 650 | |
651 | return 0; | | 651 | return 0; |
652 | } | | 652 | } |
653 | | | 653 | |
654 | static void | | 654 | static void |
655 | pthread__reap(pthread_t thread) | | 655 | pthread__reap(pthread_t thread) |
656 | { | | 656 | { |
657 | char *name; | | 657 | char *name; |
658 | | | 658 | |
659 | name = thread->pt_name; | | 659 | name = thread->pt_name; |
660 | thread->pt_name = NULL; | | 660 | thread->pt_name = NULL; |
661 | thread->pt_state = PT_STATE_DEAD; | | 661 | thread->pt_state = PT_STATE_DEAD; |
662 | pthread_mutex_unlock(&thread->pt_lock); | | 662 | pthread_mutex_unlock(&thread->pt_lock); |
663 | | | 663 | |
664 | pthread_mutex_lock(&pthread__deadqueue_lock); | | 664 | pthread_mutex_lock(&pthread__deadqueue_lock); |
665 | PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_deadq); | | 665 | PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_deadq); |
666 | pthread_mutex_unlock(&pthread__deadqueue_lock); | | 666 | pthread_mutex_unlock(&pthread__deadqueue_lock); |
667 | | | 667 | |
668 | if (name != NULL) | | 668 | if (name != NULL) |
669 | free(name); | | 669 | free(name); |
670 | } | | 670 | } |
671 | | | 671 | |
672 | int | | 672 | int |
673 | pthread_equal(pthread_t t1, pthread_t t2) | | 673 | pthread_equal(pthread_t t1, pthread_t t2) |
674 | { | | 674 | { |
675 | | | 675 | |
676 | /* Nothing special here. */ | | 676 | /* Nothing special here. */ |
677 | return (t1 == t2); | | 677 | return (t1 == t2); |
678 | } | | 678 | } |
679 | | | 679 | |
680 | | | 680 | |
681 | int | | 681 | int |
682 | pthread_detach(pthread_t thread) | | 682 | pthread_detach(pthread_t thread) |
683 | { | | 683 | { |
684 | | | 684 | |
685 | if (pthread__find(thread) != 0) | | 685 | if (pthread__find(thread) != 0) |
686 | return ESRCH; | | 686 | return ESRCH; |
687 | | | 687 | |
688 | if (thread->pt_magic != PT_MAGIC) | | 688 | if (thread->pt_magic != PT_MAGIC) |
689 | return EINVAL; | | 689 | return EINVAL; |
690 | | | 690 | |
691 | pthread_mutex_lock(&thread->pt_lock); | | 691 | pthread_mutex_lock(&thread->pt_lock); |
692 | thread->pt_flags |= PT_FLAG_DETACHED; | | 692 | thread->pt_flags |= PT_FLAG_DETACHED; |
693 | if (thread->pt_state == PT_STATE_ZOMBIE) { | | 693 | if (thread->pt_state == PT_STATE_ZOMBIE) { |
694 | /* pthread__reap() will drop the lock. */ | | 694 | /* pthread__reap() will drop the lock. */ |
695 | pthread__reap(thread); | | 695 | pthread__reap(thread); |
696 | } else { | | 696 | } else { |
697 | /* | | 697 | /* |
698 | * Not valid for threads to be waiting in | | 698 | * Not valid for threads to be waiting in |
699 | * pthread_join() (there are intractable | | 699 | * pthread_join() (there are intractable |
700 | * sync issues from the application | | 700 | * sync issues from the application |
701 | * perspective), but give those threads | | 701 | * perspective), but give those threads |
702 | * a chance anyway. | | 702 | * a chance anyway. |
703 | */ | | 703 | */ |
704 | pthread_cond_broadcast(&thread->pt_joiners); | | 704 | pthread_cond_broadcast(&thread->pt_joiners); |
705 | pthread_mutex_unlock(&thread->pt_lock); | | 705 | pthread_mutex_unlock(&thread->pt_lock); |
706 | } | | 706 | } |
707 | | | 707 | |
708 | return 0; | | 708 | return 0; |
709 | } | | 709 | } |
710 | | | 710 | |
711 | | | 711 | |
712 | int | | 712 | int |
713 | pthread_getname_np(pthread_t thread, char *name, size_t len) | | 713 | pthread_getname_np(pthread_t thread, char *name, size_t len) |
714 | { | | 714 | { |
715 | | | 715 | |
716 | if (pthread__find(thread) != 0) | | 716 | if (pthread__find(thread) != 0) |
717 | return ESRCH; | | 717 | return ESRCH; |
718 | | | 718 | |
719 | if (thread->pt_magic != PT_MAGIC) | | 719 | if (thread->pt_magic != PT_MAGIC) |
720 | return EINVAL; | | 720 | return EINVAL; |
721 | | | 721 | |
722 | pthread_mutex_lock(&thread->pt_lock); | | 722 | pthread_mutex_lock(&thread->pt_lock); |
723 | if (thread->pt_name == NULL) | | 723 | if (thread->pt_name == NULL) |
724 | name[0] = '\0'; | | 724 | name[0] = '\0'; |
725 | else | | 725 | else |
726 | strlcpy(name, thread->pt_name, len); | | 726 | strlcpy(name, thread->pt_name, len); |
727 | pthread_mutex_unlock(&thread->pt_lock); | | 727 | pthread_mutex_unlock(&thread->pt_lock); |
728 | | | 728 | |
729 | return 0; | | 729 | return 0; |
730 | } | | 730 | } |
731 | | | 731 | |
732 | | | 732 | |
733 | int | | 733 | int |
734 | pthread_setname_np(pthread_t thread, const char *name, void *arg) | | 734 | pthread_setname_np(pthread_t thread, const char *name, void *arg) |
735 | { | | 735 | { |
736 | char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP]; | | 736 | char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP]; |
737 | int namelen; | | 737 | int namelen; |
738 | | | 738 | |
739 | if (pthread__find(thread) != 0) | | 739 | if (pthread__find(thread) != 0) |
740 | return ESRCH; | | 740 | return ESRCH; |
741 | | | 741 | |
742 | if (thread->pt_magic != PT_MAGIC) | | 742 | if (thread->pt_magic != PT_MAGIC) |
743 | return EINVAL; | | 743 | return EINVAL; |
744 | | | 744 | |
745 | namelen = snprintf(newname, sizeof(newname), name, arg); | | 745 | namelen = snprintf(newname, sizeof(newname), name, arg); |
746 | if (namelen >= PTHREAD_MAX_NAMELEN_NP) | | 746 | if (namelen >= PTHREAD_MAX_NAMELEN_NP) |
747 | return EINVAL; | | 747 | return EINVAL; |
748 | | | 748 | |
749 | cp = strdup(newname); | | 749 | cp = strdup(newname); |
750 | if (cp == NULL) | | 750 | if (cp == NULL) |
751 | return ENOMEM; | | 751 | return ENOMEM; |
752 | | | 752 | |
753 | pthread_mutex_lock(&thread->pt_lock); | | 753 | pthread_mutex_lock(&thread->pt_lock); |
754 | oldname = thread->pt_name; | | 754 | oldname = thread->pt_name; |
755 | thread->pt_name = cp; | | 755 | thread->pt_name = cp; |
756 | (void)_lwp_setname(thread->pt_lid, cp); | | 756 | (void)_lwp_setname(thread->pt_lid, cp); |
757 | pthread_mutex_unlock(&thread->pt_lock); | | 757 | pthread_mutex_unlock(&thread->pt_lock); |
758 | | | 758 | |
759 | if (oldname != NULL) | | 759 | if (oldname != NULL) |
760 | free(oldname); | | 760 | free(oldname); |
761 | | | 761 | |
762 | return 0; | | 762 | return 0; |
763 | } | | 763 | } |
764 | | | 764 | |
765 | | | 765 | |
766 | | | 766 | |
767 | /* | | 767 | /* |
768 | * XXX There should be a way for applications to use the efficent | | 768 | * XXX There should be a way for applications to use the efficent |
769 | * inline version, but there are opacity/namespace issues. | | 769 | * inline version, but there are opacity/namespace issues. |
770 | */ | | 770 | */ |
771 | pthread_t | | 771 | pthread_t |
772 | pthread_self(void) | | 772 | pthread_self(void) |
773 | { | | 773 | { |
774 | | | 774 | |
775 | return pthread__self(); | | 775 | return pthread__self(); |
776 | } | | 776 | } |
777 | | | 777 | |
778 | | | 778 | |
779 | int | | 779 | int |
780 | pthread_cancel(pthread_t thread) | | 780 | pthread_cancel(pthread_t thread) |
781 | { | | 781 | { |
782 | | | 782 | |
783 | if (pthread__find(thread) != 0) | | 783 | if (pthread__find(thread) != 0) |
784 | return ESRCH; | | 784 | return ESRCH; |
785 | pthread_mutex_lock(&thread->pt_lock); | | 785 | pthread_mutex_lock(&thread->pt_lock); |
786 | thread->pt_flags |= PT_FLAG_CS_PENDING; | | 786 | thread->pt_flags |= PT_FLAG_CS_PENDING; |
787 | if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) { | | 787 | if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) { |
788 | thread->pt_cancel = 1; | | 788 | thread->pt_cancel = 1; |
789 | pthread_mutex_unlock(&thread->pt_lock); | | 789 | pthread_mutex_unlock(&thread->pt_lock); |
790 | _lwp_wakeup(thread->pt_lid); | | 790 | _lwp_wakeup(thread->pt_lid); |
791 | } else | | 791 | } else |
792 | pthread_mutex_unlock(&thread->pt_lock); | | 792 | pthread_mutex_unlock(&thread->pt_lock); |
793 | | | 793 | |
794 | return 0; | | 794 | return 0; |
795 | } | | 795 | } |
796 | | | 796 | |
797 | | | 797 | |
798 | int | | 798 | int |
799 | pthread_setcancelstate(int state, int *oldstate) | | 799 | pthread_setcancelstate(int state, int *oldstate) |
800 | { | | 800 | { |
801 | pthread_t self; | | 801 | pthread_t self; |
802 | int retval; | | 802 | int retval; |
803 | | | 803 | |
804 | self = pthread__self(); | | 804 | self = pthread__self(); |
805 | retval = 0; | | 805 | retval = 0; |
806 | | | 806 | |
807 | pthread_mutex_lock(&self->pt_lock); | | 807 | pthread_mutex_lock(&self->pt_lock); |
808 | | | 808 | |
809 | if (oldstate != NULL) { | | 809 | if (oldstate != NULL) { |
810 | if (self->pt_flags & PT_FLAG_CS_DISABLED) | | 810 | if (self->pt_flags & PT_FLAG_CS_DISABLED) |
811 | *oldstate = PTHREAD_CANCEL_DISABLE; | | 811 | *oldstate = PTHREAD_CANCEL_DISABLE; |
812 | else | | 812 | else |
813 | *oldstate = PTHREAD_CANCEL_ENABLE; | | 813 | *oldstate = PTHREAD_CANCEL_ENABLE; |
814 | } | | 814 | } |
815 | | | 815 | |
816 | if (state == PTHREAD_CANCEL_DISABLE) { | | 816 | if (state == PTHREAD_CANCEL_DISABLE) { |
817 | self->pt_flags |= PT_FLAG_CS_DISABLED; | | 817 | self->pt_flags |= PT_FLAG_CS_DISABLED; |
818 | if (self->pt_cancel) { | | 818 | if (self->pt_cancel) { |
819 | self->pt_flags |= PT_FLAG_CS_PENDING; | | 819 | self->pt_flags |= PT_FLAG_CS_PENDING; |
820 | self->pt_cancel = 0; | | 820 | self->pt_cancel = 0; |
821 | } | | 821 | } |
822 | } else if (state == PTHREAD_CANCEL_ENABLE) { | | 822 | } else if (state == PTHREAD_CANCEL_ENABLE) { |
823 | self->pt_flags &= ~PT_FLAG_CS_DISABLED; | | 823 | self->pt_flags &= ~PT_FLAG_CS_DISABLED; |
824 | /* | | 824 | /* |
825 | * If a cancellation was requested while cancellation | | 825 | * If a cancellation was requested while cancellation |
826 | * was disabled, note that fact for future | | 826 | * was disabled, note that fact for future |
827 | * cancellation tests. | | 827 | * cancellation tests. |
828 | */ | | 828 | */ |
829 | if (self->pt_flags & PT_FLAG_CS_PENDING) { | | 829 | if (self->pt_flags & PT_FLAG_CS_PENDING) { |
830 | self->pt_cancel = 1; | | 830 | self->pt_cancel = 1; |
831 | /* This is not a deferred cancellation point. */ | | 831 | /* This is not a deferred cancellation point. */ |
832 | if (self->pt_flags & PT_FLAG_CS_ASYNC) { | | 832 | if (self->pt_flags & PT_FLAG_CS_ASYNC) { |
833 | pthread_mutex_unlock(&self->pt_lock); | | 833 | pthread_mutex_unlock(&self->pt_lock); |
834 | pthread__cancelled(); | | 834 | pthread__cancelled(); |
835 | } | | 835 | } |
836 | } | | 836 | } |
837 | } else | | 837 | } else |
838 | retval = EINVAL; | | 838 | retval = EINVAL; |
839 | | | 839 | |
840 | pthread_mutex_unlock(&self->pt_lock); | | 840 | pthread_mutex_unlock(&self->pt_lock); |
841 | | | 841 | |
842 | return retval; | | 842 | return retval; |
843 | } | | 843 | } |
844 | | | 844 | |
845 | | | 845 | |
846 | int | | 846 | int |
847 | pthread_setcanceltype(int type, int *oldtype) | | 847 | pthread_setcanceltype(int type, int *oldtype) |
848 | { | | 848 | { |
849 | pthread_t self; | | 849 | pthread_t self; |
850 | int retval; | | 850 | int retval; |
851 | | | 851 | |
852 | self = pthread__self(); | | 852 | self = pthread__self(); |
853 | retval = 0; | | 853 | retval = 0; |
854 | | | 854 | |
855 | pthread_mutex_lock(&self->pt_lock); | | 855 | pthread_mutex_lock(&self->pt_lock); |
856 | | | 856 | |
857 | if (oldtype != NULL) { | | 857 | if (oldtype != NULL) { |
858 | if (self->pt_flags & PT_FLAG_CS_ASYNC) | | 858 | if (self->pt_flags & PT_FLAG_CS_ASYNC) |
859 | *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; | | 859 | *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; |
860 | else | | 860 | else |
861 | *oldtype = PTHREAD_CANCEL_DEFERRED; | | 861 | *oldtype = PTHREAD_CANCEL_DEFERRED; |
862 | } | | 862 | } |
863 | | | 863 | |
864 | if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { | | 864 | if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { |
865 | self->pt_flags |= PT_FLAG_CS_ASYNC; | | 865 | self->pt_flags |= PT_FLAG_CS_ASYNC; |
866 | if (self->pt_cancel) { | | 866 | if (self->pt_cancel) { |
867 | pthread_mutex_unlock(&self->pt_lock); | | 867 | pthread_mutex_unlock(&self->pt_lock); |
868 | pthread__cancelled(); | | 868 | pthread__cancelled(); |
869 | } | | 869 | } |
870 | } else if (type == PTHREAD_CANCEL_DEFERRED) | | 870 | } else if (type == PTHREAD_CANCEL_DEFERRED) |
871 | self->pt_flags &= ~PT_FLAG_CS_ASYNC; | | 871 | self->pt_flags &= ~PT_FLAG_CS_ASYNC; |
872 | else | | 872 | else |
873 | retval = EINVAL; | | 873 | retval = EINVAL; |
874 | | | 874 | |
875 | pthread_mutex_unlock(&self->pt_lock); | | 875 | pthread_mutex_unlock(&self->pt_lock); |
876 | | | 876 | |
877 | return retval; | | 877 | return retval; |
878 | } | | 878 | } |
879 | | | 879 | |
880 | | | 880 | |
881 | void | | 881 | void |
882 | pthread_testcancel(void) | | 882 | pthread_testcancel(void) |
883 | { | | 883 | { |
884 | pthread_t self; | | 884 | pthread_t self; |
885 | | | 885 | |
886 | self = pthread__self(); | | 886 | self = pthread__self(); |
887 | if (self->pt_cancel) | | 887 | if (self->pt_cancel) |
888 | pthread__cancelled(); | | 888 | pthread__cancelled(); |
889 | } | | 889 | } |
890 | | | 890 | |
891 | | | 891 | |
892 | /* | | 892 | /* |
893 | * POSIX requires that certain functions return an error rather than | | 893 | * POSIX requires that certain functions return an error rather than |
894 | * invoking undefined behavior even when handed completely bogus | | 894 | * invoking undefined behavior even when handed completely bogus |
895 | * pthread_t values, e.g. stack garbage or (pthread_t)666. This | | 895 | * pthread_t values, e.g. stack garbage or (pthread_t)666. This |
896 | * utility routine searches the list of threads for the pthread_t | | 896 | * utility routine searches the list of threads for the pthread_t |
897 | * value without dereferencing it. | | 897 | * value without dereferencing it. |
898 | */ | | 898 | */ |
899 | int | | 899 | int |
900 | pthread__find(pthread_t id) | | 900 | pthread__find(pthread_t id) |
901 | { | | 901 | { |
902 | pthread_t target; | | 902 | pthread_t target; |
903 | | | 903 | |
904 | pthread_rwlock_rdlock(&pthread__alltree_lock); | | 904 | pthread_rwlock_rdlock(&pthread__alltree_lock); |
905 | /* LINTED */ | | 905 | /* LINTED */ |
906 | target = RB_FIND(__pthread__alltree, &pthread__alltree, id); | | 906 | target = RB_FIND(__pthread__alltree, &pthread__alltree, id); |
907 | pthread_rwlock_unlock(&pthread__alltree_lock); | | 907 | pthread_rwlock_unlock(&pthread__alltree_lock); |
908 | | | 908 | |
909 | if (target == NULL || target->pt_state == PT_STATE_DEAD) | | 909 | if (target == NULL || target->pt_state == PT_STATE_DEAD) |
910 | return ESRCH; | | 910 | return ESRCH; |
911 | | | 911 | |
912 | return 0; | | 912 | return 0; |
913 | } | | 913 | } |
914 | | | 914 | |
915 | | | 915 | |
916 | void | | 916 | void |
917 | pthread__testcancel(pthread_t self) | | 917 | pthread__testcancel(pthread_t self) |
918 | { | | 918 | { |
919 | | | 919 | |
920 | if (self->pt_cancel) | | 920 | if (self->pt_cancel) |
921 | pthread__cancelled(); | | 921 | pthread__cancelled(); |
922 | } | | 922 | } |
923 | | | 923 | |
924 | | | 924 | |
925 | void | | 925 | void |
926 | pthread__cancelled(void) | | 926 | pthread__cancelled(void) |
927 | { | | 927 | { |
928 | pthread_mutex_t *droplock; | | 928 | pthread_mutex_t *droplock; |
929 | pthread_t self; | | 929 | pthread_t self; |
930 | | | 930 | |
931 | self = pthread__self(); | | 931 | self = pthread__self(); |
932 | droplock = self->pt_droplock; | | 932 | droplock = self->pt_droplock; |
933 | self->pt_droplock = NULL; | | 933 | self->pt_droplock = NULL; |
934 | | | 934 | |
935 | if (droplock != NULL && pthread_mutex_held_np(droplock)) | | 935 | if (droplock != NULL && pthread_mutex_held_np(droplock)) |
936 | pthread_mutex_unlock(droplock); | | 936 | pthread_mutex_unlock(droplock); |
937 | | | 937 | |
938 | pthread_exit(PTHREAD_CANCELED); | | 938 | pthread_exit(PTHREAD_CANCELED); |
939 | } | | 939 | } |
940 | | | 940 | |
941 | | | 941 | |
942 | void | | 942 | void |
943 | pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store) | | 943 | pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store) |
944 | { | | 944 | { |
945 | pthread_t self; | | 945 | pthread_t self; |
946 | struct pt_clean_t *entry; | | 946 | struct pt_clean_t *entry; |
947 | | | 947 | |
948 | self = pthread__self(); | | 948 | self = pthread__self(); |
949 | entry = store; | | 949 | entry = store; |
950 | entry->ptc_cleanup = cleanup; | | 950 | entry->ptc_cleanup = cleanup; |
951 | entry->ptc_arg = arg; | | 951 | entry->ptc_arg = arg; |
952 | PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next); | | 952 | PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next); |
953 | } | | 953 | } |
954 | | | 954 | |
955 | | | 955 | |
956 | void | | 956 | void |
957 | pthread__cleanup_pop(int ex, void *store) | | 957 | pthread__cleanup_pop(int ex, void *store) |
958 | { | | 958 | { |
959 | pthread_t self; | | 959 | pthread_t self; |
960 | struct pt_clean_t *entry; | | 960 | struct pt_clean_t *entry; |
961 | | | 961 | |
962 | self = pthread__self(); | | 962 | self = pthread__self(); |
963 | entry = store; | | 963 | entry = store; |
964 | | | 964 | |
965 | PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next); | | 965 | PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next); |
966 | if (ex) | | 966 | if (ex) |
967 | (*entry->ptc_cleanup)(entry->ptc_arg); | | 967 | (*entry->ptc_cleanup)(entry->ptc_arg); |
968 | } | | 968 | } |
969 | | | 969 | |
970 | | | 970 | |
971 | int * | | 971 | int * |
972 | pthread__errno(void) | | 972 | pthread__errno(void) |
973 | { | | 973 | { |
974 | pthread_t self; | | 974 | pthread_t self; |
975 | | | 975 | |
976 | self = pthread__self(); | | 976 | self = pthread__self(); |
977 | | | 977 | |
978 | return &(self->pt_errno); | | 978 | return &(self->pt_errno); |
979 | } | | 979 | } |
980 | | | 980 | |
981 | ssize_t _sys_write(int, const void *, size_t); | | 981 | ssize_t _sys_write(int, const void *, size_t); |
982 | | | 982 | |
983 | void | | 983 | void |
984 | pthread__assertfunc(const char *file, int line, const char *function, | | 984 | pthread__assertfunc(const char *file, int line, const char *function, |
985 | const char *expr) | | 985 | const char *expr) |
986 | { | | 986 | { |
987 | char buf[1024]; | | 987 | char buf[1024]; |
988 | int len; | | 988 | int len; |
989 | | | 989 | |
990 | /* | | 990 | /* |
991 | * snprintf should not acquire any locks, or we could | | 991 | * snprintf should not acquire any locks, or we could |
992 | * end up deadlocked if the assert caller held locks. | | 992 | * end up deadlocked if the assert caller held locks. |
993 | */ | | 993 | */ |
994 | len = snprintf(buf, 1024, | | 994 | len = snprintf(buf, 1024, |
995 | "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n", | | 995 | "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n", |
996 | expr, file, line, | | 996 | expr, file, line, |
997 | function ? ", function \"" : "", | | 997 | function ? ", function \"" : "", |
998 | function ? function : "", | | 998 | function ? function : "", |
999 | function ? "\"" : ""); | | 999 | function ? "\"" : ""); |
1000 | | | 1000 | |
1001 | _sys_write(STDERR_FILENO, buf, (size_t)len); | | 1001 | _sys_write(STDERR_FILENO, buf, (size_t)len); |
1002 | (void)kill(getpid(), SIGABRT); | | 1002 | (void)kill(getpid(), SIGABRT); |
1003 | | | 1003 | |
1004 | _exit(1); | | 1004 | _exit(1); |
1005 | } | | 1005 | } |
1006 | | | 1006 | |
1007 | | | 1007 | |
1008 | void | | 1008 | void |
1009 | pthread__errorfunc(const char *file, int line, const char *function, | | 1009 | pthread__errorfunc(const char *file, int line, const char *function, |
1010 | const char *msg) | | 1010 | const char *msg) |
1011 | { | | 1011 | { |
1012 | char buf[1024]; | | 1012 | char buf[1024]; |
1013 | size_t len; | | 1013 | size_t len; |
1014 | | | 1014 | |
1015 | if (pthread__diagassert == 0) | | 1015 | if (pthread__diagassert == 0) |
1016 | return; | | 1016 | return; |
1017 | | | 1017 | |
1018 | /* | | 1018 | /* |
1019 | * snprintf should not acquire any locks, or we could | | 1019 | * snprintf should not acquire any locks, or we could |
1020 | * end up deadlocked if the assert caller held locks. | | 1020 | * end up deadlocked if the assert caller held locks. |
1021 | */ | | 1021 | */ |
1022 | len = snprintf(buf, 1024, | | 1022 | len = snprintf(buf, 1024, |
1023 | "%s: Error detected by libpthread: %s.\n" | | 1023 | "%s: Error detected by libpthread: %s.\n" |
1024 | "Detected by file \"%s\", line %d%s%s%s.\n" | | 1024 | "Detected by file \"%s\", line %d%s%s%s.\n" |
1025 | "See pthread(3) for information.\n", | | 1025 | "See pthread(3) for information.\n", |
1026 | getprogname(), msg, file, line, | | 1026 | getprogname(), msg, file, line, |
1027 | function ? ", function \"" : "", | | 1027 | function ? ", function \"" : "", |
1028 | function ? function : "", | | 1028 | function ? function : "", |
1029 | function ? "\"" : ""); | | 1029 | function ? "\"" : ""); |
1030 | | | 1030 | |
1031 | if (pthread__diagassert & DIAGASSERT_STDERR) | | 1031 | if (pthread__diagassert & DIAGASSERT_STDERR) |
1032 | _sys_write(STDERR_FILENO, buf, len); | | 1032 | _sys_write(STDERR_FILENO, buf, len); |
1033 | | | 1033 | |
1034 | if (pthread__diagassert & DIAGASSERT_SYSLOG) | | 1034 | if (pthread__diagassert & DIAGASSERT_SYSLOG) |
1035 | syslog(LOG_DEBUG | LOG_USER, "%s", buf); | | 1035 | syslog(LOG_DEBUG | LOG_USER, "%s", buf); |
1036 | | | 1036 | |
1037 | if (pthread__diagassert & DIAGASSERT_ABORT) { | | 1037 | if (pthread__diagassert & DIAGASSERT_ABORT) { |
1038 | (void)kill(getpid(), SIGABRT); | | 1038 | (void)kill(getpid(), SIGABRT); |
1039 | _exit(1); | | 1039 | _exit(1); |
1040 | } | | 1040 | } |
1041 | } | | 1041 | } |
1042 | | | 1042 | |
1043 | /* | | 1043 | /* |
1044 | * Thread park/unpark operations. The kernel operations are | | 1044 | * Thread park/unpark operations. The kernel operations are |
1045 | * modelled after a brief description from "Multithreading in | | 1045 | * modelled after a brief description from "Multithreading in |
1046 | * the Solaris Operating Environment": | | 1046 | * the Solaris Operating Environment": |
1047 | * | | 1047 | * |
1048 | * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf | | 1048 | * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf |
1049 | */ | | 1049 | */ |
1050 | | | 1050 | |
1051 | #define OOPS(msg) \ | | 1051 | #define OOPS(msg) \ |
1052 | pthread__errorfunc(__FILE__, __LINE__, __func__, msg) | | 1052 | pthread__errorfunc(__FILE__, __LINE__, __func__, msg) |
1053 | | | 1053 | |
1054 | int | | 1054 | int |
1055 | pthread__park(pthread_t self, pthread_mutex_t *lock, | | 1055 | pthread__park(pthread_t self, pthread_mutex_t *lock, |
1056 | pthread_queue_t *queue, const struct timespec *abstime, | | 1056 | pthread_queue_t *queue, const struct timespec *abstime, |
1057 | int cancelpt, const void *hint) | | 1057 | int cancelpt, const void *hint) |
1058 | { | | 1058 | { |
1059 | int rv, error; | | 1059 | int rv, error; |
1060 | void *obj; | | 1060 | void *obj; |
1061 | | | 1061 | |
1062 | /* | | 1062 | /* |
1063 | * For non-interlocked release of mutexes we need a store | | 1063 | * For non-interlocked release of mutexes we need a store |
1064 | * barrier before incrementing pt_blocking away from zero. | | 1064 | * barrier before incrementing pt_blocking away from zero. |
1065 | * This is provided by pthread_mutex_unlock(). | | 1065 | * This is provided by pthread_mutex_unlock(). |
1066 | */ | | 1066 | */ |
1067 | self->pt_willpark = 1; | | 1067 | self->pt_willpark = 1; |
1068 | pthread_mutex_unlock(lock); | | 1068 | pthread_mutex_unlock(lock); |
1069 | self->pt_willpark = 0; | | 1069 | self->pt_willpark = 0; |
1070 | self->pt_blocking++; | | 1070 | self->pt_blocking++; |
1071 | | | 1071 | |
1072 | /* | | 1072 | /* |
1073 | * Wait until we are awoken by a pending unpark operation, | | 1073 | * Wait until we are awoken by a pending unpark operation, |
1074 | * a signal, an unpark posted after we have gone asleep, | | 1074 | * a signal, an unpark posted after we have gone asleep, |
1075 | * or an expired timeout. | | 1075 | * or an expired timeout. |
1076 | * | | 1076 | * |
1077 | * It is fine to test the value of pt_sleepobj without | | 1077 | * It is fine to test the value of pt_sleepobj without |
1078 | * holding any locks, because: | | 1078 | * holding any locks, because: |
1079 | * | | 1079 | * |
1080 | * o Only the blocking thread (this thread) ever sets them | | 1080 | * o Only the blocking thread (this thread) ever sets them |
1081 | * to a non-NULL value. | | 1081 | * to a non-NULL value. |
1082 | * | | 1082 | * |
1083 | * o Other threads may set them NULL, but if they do so they | | 1083 | * o Other threads may set them NULL, but if they do so they |
1084 | * must also make this thread return from _lwp_park. | | 1084 | * must also make this thread return from _lwp_park. |
1085 | * | | 1085 | * |
1086 | * o _lwp_park, _lwp_unpark and _lwp_unpark_all are system | | 1086 | * o _lwp_park, _lwp_unpark and _lwp_unpark_all are system |
1087 | * calls and all make use of spinlocks in the kernel. So | | 1087 | * calls and all make use of spinlocks in the kernel. So |
1088 | * these system calls act as full memory barriers, and will | | 1088 | * these system calls act as full memory barriers, and will |
1089 | * ensure that the calling CPU's store buffers are drained. | | 1089 | * ensure that the calling CPU's store buffers are drained. |
1090 | * In combination with the spinlock release before unpark, | | 1090 | * In combination with the spinlock release before unpark, |
1091 | * this means that modification of pt_sleepobj/onq by another | | 1091 | * this means that modification of pt_sleepobj/onq by another |
1092 | * thread will become globally visible before that thread | | 1092 | * thread will become globally visible before that thread |
1093 | * schedules an unpark operation on this thread. | | 1093 | * schedules an unpark operation on this thread. |
1094 | * | | 1094 | * |
1095 | * Note: the test in the while() statement dodges the park op if | | 1095 | * Note: the test in the while() statement dodges the park op if |
1096 | * we have already been awoken, unless there is another thread to | | 1096 | * we have already been awoken, unless there is another thread to |
1097 | * awaken. This saves a syscall - if we were already awakened, | | 1097 | * awaken. This saves a syscall - if we were already awakened, |
1098 | * the next call to _lwp_park() would need to return early in order | | 1098 | * the next call to _lwp_park() would need to return early in order |
1099 | * to eat the previous wakeup. | | 1099 | * to eat the previous wakeup. |
1100 | */ | | 1100 | */ |
1101 | rv = 0; | | 1101 | rv = 0; |
1102 | do { | | 1102 | do { |
1103 | /* | | 1103 | /* |
1104 | * If we deferred unparking a thread, arrange to | | 1104 | * If we deferred unparking a thread, arrange to |
1105 | * have _lwp_park() restart it before blocking. | | 1105 | * have _lwp_park() restart it before blocking. |
1106 | */ | | 1106 | */ |
1107 | error = _lwp_park(abstime, self->pt_unpark, hint, hint); | | 1107 | error = _lwp_park(abstime, self->pt_unpark, hint, hint); |
1108 | self->pt_unpark = 0; | | 1108 | self->pt_unpark = 0; |
1109 | if (error != 0) { | | 1109 | if (error != 0) { |
1110 | switch (rv = errno) { | | 1110 | switch (rv = errno) { |
1111 | case EINTR: | | 1111 | case EINTR: |
1112 | case EALREADY: | | 1112 | case EALREADY: |
1113 | rv = 0; | | 1113 | rv = 0; |
1114 | break; | | 1114 | break; |
1115 | case ETIMEDOUT: | | 1115 | case ETIMEDOUT: |
1116 | break; | | 1116 | break; |
1117 | default: | | 1117 | default: |
1118 | OOPS("_lwp_park failed"); | | 1118 | OOPS("_lwp_park failed"); |
1119 | break; | | 1119 | break; |
1120 | } | | 1120 | } |
1121 | } | | 1121 | } |
1122 | /* Check for cancellation. */ | | 1122 | /* Check for cancellation. */ |
1123 | if (cancelpt && self->pt_cancel) | | 1123 | if (cancelpt && self->pt_cancel) |
1124 | rv = EINTR; | | 1124 | rv = EINTR; |
1125 | } while (self->pt_sleepobj != NULL && rv == 0); | | 1125 | } while (self->pt_sleepobj != NULL && rv == 0); |
1126 | | | 1126 | |
1127 | /* | | 1127 | /* |
1128 | * If we have been awoken early but are still on the queue, | | 1128 | * If we have been awoken early but are still on the queue, |
1129 | * then remove ourself. Again, it's safe to do the test | | 1129 | * then remove ourself. Again, it's safe to do the test |
1130 | * without holding any locks. | | 1130 | * without holding any locks. |
1131 | */ | | 1131 | */ |
1132 | if (__predict_false(self->pt_sleepobj != NULL)) { | | 1132 | if (__predict_false(self->pt_sleepobj != NULL)) { |
1133 | pthread_mutex_lock(lock); | | 1133 | pthread_mutex_lock(lock); |
1134 | if ((obj = self->pt_sleepobj) != NULL) { | | 1134 | if ((obj = self->pt_sleepobj) != NULL) { |
1135 | PTQ_REMOVE(queue, self, pt_sleep); | | 1135 | PTQ_REMOVE(queue, self, pt_sleep); |
1136 | self->pt_sleepobj = NULL; | | 1136 | self->pt_sleepobj = NULL; |
1137 | if (obj != NULL && self->pt_early != NULL) | | 1137 | if (obj != NULL && self->pt_early != NULL) |
1138 | (*self->pt_early)(obj); | | 1138 | (*self->pt_early)(obj); |
1139 | } | | 1139 | } |
1140 | pthread_mutex_unlock(lock); | | 1140 | pthread_mutex_unlock(lock); |
1141 | } | | 1141 | } |
1142 | self->pt_early = NULL; | | 1142 | self->pt_early = NULL; |
1143 | self->pt_blocking--; | | 1143 | self->pt_blocking--; |
1144 | membar_sync(); | | 1144 | membar_sync(); |
1145 | | | 1145 | |
1146 | return rv; | | 1146 | return rv; |
1147 | } | | 1147 | } |
1148 | | | 1148 | |
1149 | void | | 1149 | void |
1150 | pthread__unpark(pthread_queue_t *queue, pthread_t self, | | 1150 | pthread__unpark(pthread_queue_t *queue, pthread_t self, |
1151 | pthread_mutex_t *interlock) | | 1151 | pthread_mutex_t *interlock) |
1152 | { | | 1152 | { |
1153 | pthread_t target; | | 1153 | pthread_t target; |
1154 | u_int max; | | 1154 | u_int max; |
1155 | size_t nwaiters; | | 1155 | size_t nwaiters; |
1156 | | | 1156 | |
1157 | max = pthread__unpark_max; | | 1157 | max = pthread__unpark_max; |
1158 | nwaiters = self->pt_nwaiters; | | 1158 | nwaiters = self->pt_nwaiters; |
1159 | target = PTQ_FIRST(queue); | | 1159 | target = PTQ_FIRST(queue); |
1160 | if (nwaiters == max) { | | 1160 | if (nwaiters == max) { |
1161 | /* Overflow. */ | | 1161 | /* Overflow. */ |
1162 | (void)_lwp_unpark_all(self->pt_waiters, nwaiters, | | 1162 | (void)_lwp_unpark_all(self->pt_waiters, nwaiters, |
1163 | __UNVOLATILE(&interlock->ptm_waiters)); | | 1163 | __UNVOLATILE(&interlock->ptm_waiters)); |
1164 | nwaiters = 0; | | 1164 | nwaiters = 0; |
1165 | } | | 1165 | } |
1166 | target->pt_sleepobj = NULL; | | 1166 | target->pt_sleepobj = NULL; |
1167 | self->pt_waiters[nwaiters++] = target->pt_lid; | | 1167 | self->pt_waiters[nwaiters++] = target->pt_lid; |
1168 | PTQ_REMOVE(queue, target, pt_sleep); | | 1168 | PTQ_REMOVE(queue, target, pt_sleep); |
1169 | self->pt_nwaiters = nwaiters; | | 1169 | self->pt_nwaiters = nwaiters; |
1170 | pthread__mutex_deferwake(self, interlock); | | 1170 | pthread__mutex_deferwake(self, interlock); |
1171 | } | | 1171 | } |
1172 | | | 1172 | |
1173 | void | | 1173 | void |
1174 | pthread__unpark_all(pthread_queue_t *queue, pthread_t self, | | 1174 | pthread__unpark_all(pthread_queue_t *queue, pthread_t self, |
1175 | pthread_mutex_t *interlock) | | 1175 | pthread_mutex_t *interlock) |
1176 | { | | 1176 | { |
1177 | pthread_t target; | | 1177 | pthread_t target; |
1178 | u_int max; | | 1178 | u_int max; |
1179 | size_t nwaiters; | | 1179 | size_t nwaiters; |
1180 | | | 1180 | |
1181 | max = pthread__unpark_max; | | 1181 | max = pthread__unpark_max; |
1182 | nwaiters = self->pt_nwaiters; | | 1182 | nwaiters = self->pt_nwaiters; |
1183 | PTQ_FOREACH(target, queue, pt_sleep) { | | 1183 | PTQ_FOREACH(target, queue, pt_sleep) { |
1184 | if (nwaiters == max) { | | 1184 | if (nwaiters == max) { |
1185 | /* Overflow. */ | | 1185 | /* Overflow. */ |
1186 | (void)_lwp_unpark_all(self->pt_waiters, nwaiters, | | 1186 | (void)_lwp_unpark_all(self->pt_waiters, nwaiters, |
1187 | __UNVOLATILE(&interlock->ptm_waiters)); | | 1187 | __UNVOLATILE(&interlock->ptm_waiters)); |
1188 | nwaiters = 0; | | 1188 | nwaiters = 0; |
1189 | } | | 1189 | } |
1190 | target->pt_sleepobj = NULL; | | 1190 | target->pt_sleepobj = NULL; |
1191 | self->pt_waiters[nwaiters++] = target->pt_lid; | | 1191 | self->pt_waiters[nwaiters++] = target->pt_lid; |
1192 | } | | 1192 | } |
1193 | self->pt_nwaiters = nwaiters; | | 1193 | self->pt_nwaiters = nwaiters; |
1194 | PTQ_INIT(queue); | | 1194 | PTQ_INIT(queue); |
1195 | pthread__mutex_deferwake(self, interlock); | | 1195 | pthread__mutex_deferwake(self, interlock); |
1196 | } | | 1196 | } |
1197 | | | 1197 | |
1198 | #undef OOPS | | 1198 | #undef OOPS |
1199 | | | 1199 | |
1200 | static void | | 1200 | static void |
1201 | pthread__initmainstack(void) | | 1201 | pthread__initmainstack(void) |
1202 | { | | 1202 | { |
1203 | struct rlimit slimit; | | 1203 | struct rlimit slimit; |
1204 | const AuxInfo *aux; | | 1204 | const AuxInfo *aux; |
| | | 1205 | size_t size; |
1205 | | | 1206 | |
1206 | _DIAGASSERT(_dlauxinfo() != NULL); | | 1207 | _DIAGASSERT(_dlauxinfo() != NULL); |
1207 | | | 1208 | |
1208 | if (getrlimit(RLIMIT_STACK, &slimit) == -1) | | 1209 | if (getrlimit(RLIMIT_STACK, &slimit) == -1) |
1209 | err(1, "Couldn't get stack resource consumption limits"); | | 1210 | err(1, "Couldn't get stack resource consumption limits"); |
1210 | pthread__main.pt_stack.ss_size = slimit.rlim_cur; | | 1211 | size = slimit.rlim_cur; |
| | | 1212 | pthread__main.pt_stack.ss_size = size; |
1211 | | | 1213 | |
1212 | for (aux = _dlauxinfo(); aux->a_type != AT_NULL; ++aux) { | | 1214 | for (aux = _dlauxinfo(); aux->a_type != AT_NULL; ++aux) { |
1213 | if (aux->a_type == AT_STACKBASE) { | | 1215 | if (aux->a_type == AT_STACKBASE) { |
1214 | pthread__main.pt_stack.ss_sp = (void *)aux->a_v; | | 1216 | pthread__main.pt_stack.ss_sp = (void *)aux->a_v; |
| | | 1217 | #ifdef __MACHINE_STACK_GROWS_UP |
| | | 1218 | pthread__main.pt_stack.ss_sp = (void *)aux->a_v; |
| | | 1219 | #else |
| | | 1220 | pthread__main.pt_stack.ss_sp = (char *)aux->a_v - size; |
| | | 1221 | #endif |
1215 | break; | | 1222 | break; |
1216 | } | | 1223 | } |
1217 | } | | 1224 | } |
1218 | } | | 1225 | } |
1219 | | | 1226 | |
1220 | /* | | 1227 | /* |
1221 | * Set up the slightly special stack for the "initial" thread, which | | 1228 | * Set up the slightly special stack for the "initial" thread, which |
1222 | * runs on the normal system stack, and thus gets slightly different | | 1229 | * runs on the normal system stack, and thus gets slightly different |
1223 | * treatment. | | 1230 | * treatment. |
1224 | */ | | 1231 | */ |
1225 | static void | | 1232 | static void |
1226 | pthread__initmain(pthread_t *newt) | | 1233 | pthread__initmain(pthread_t *newt) |
1227 | { | | 1234 | { |
1228 | char *value; | | 1235 | char *value; |
1229 | | | 1236 | |
1230 | pthread__initmainstack(); | | 1237 | pthread__initmainstack(); |
1231 | | | 1238 | |
1232 | value = pthread__getenv("PTHREAD_STACKSIZE"); | | 1239 | value = pthread__getenv("PTHREAD_STACKSIZE"); |
1233 | if (value != NULL) { | | 1240 | if (value != NULL) { |
1234 | pthread__stacksize = atoi(value) * 1024; | | 1241 | pthread__stacksize = atoi(value) * 1024; |
1235 | if (pthread__stacksize > pthread__main.pt_stack.ss_size) | | 1242 | if (pthread__stacksize > pthread__main.pt_stack.ss_size) |
1236 | pthread__stacksize = pthread__main.pt_stack.ss_size; | | 1243 | pthread__stacksize = pthread__main.pt_stack.ss_size; |
1237 | } | | 1244 | } |
1238 | if (pthread__stacksize == 0) | | 1245 | if (pthread__stacksize == 0) |
1239 | pthread__stacksize = pthread__main.pt_stack.ss_size; | | 1246 | pthread__stacksize = pthread__main.pt_stack.ss_size; |
1240 | pthread__stacksize += pthread__pagesize - 1; | | 1247 | pthread__stacksize += pthread__pagesize - 1; |
1241 | pthread__stacksize &= ~pthread__pagesize; | | 1248 | pthread__stacksize &= ~pthread__pagesize; |
1242 | if (pthread__stacksize < 4 * pthread__pagesize) | | 1249 | if (pthread__stacksize < 4 * pthread__pagesize) |
1243 | errx(1, "Stacksize limit is too low, minimum %zd kbyte.", | | 1250 | errx(1, "Stacksize limit is too low, minimum %zd kbyte.", |
1244 | 4 * pthread__pagesize / 1024); | | 1251 | 4 * pthread__pagesize / 1024); |
1245 | | | 1252 | |
1246 | *newt = &pthread__main; | | 1253 | *newt = &pthread__main; |
1247 | #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) | | 1254 | #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) |
1248 | # ifdef __HAVE___LWP_GETTCB_FAST | | 1255 | # ifdef __HAVE___LWP_GETTCB_FAST |
1249 | pthread__main.pt_tls = __lwp_gettcb_fast(); | | 1256 | pthread__main.pt_tls = __lwp_gettcb_fast(); |
1250 | # else | | 1257 | # else |
1251 | pthread__main.pt_tls = _lwp_getprivate(); | | 1258 | pthread__main.pt_tls = _lwp_getprivate(); |
1252 | # endif | | 1259 | # endif |
1253 | pthread__main.pt_tls->tcb_pthread = &pthread__main; | | 1260 | pthread__main.pt_tls->tcb_pthread = &pthread__main; |
1254 | #endif | | 1261 | #endif |
1255 | } | | 1262 | } |
1256 | | | 1263 | |
1257 | #ifndef lint | | 1264 | #ifndef lint |
1258 | static int | | 1265 | static int |
1259 | pthread__cmp(struct __pthread_st *a, struct __pthread_st *b) | | 1266 | pthread__cmp(struct __pthread_st *a, struct __pthread_st *b) |
1260 | { | | 1267 | { |
1261 | | | 1268 | |
1262 | if ((uintptr_t)a < (uintptr_t)b) | | 1269 | if ((uintptr_t)a < (uintptr_t)b) |
1263 | return (-1); | | 1270 | return (-1); |
1264 | else if (a == b) | | 1271 | else if (a == b) |
1265 | return 0; | | 1272 | return 0; |
1266 | else | | 1273 | else |
1267 | return 1; | | 1274 | return 1; |
1268 | } | | 1275 | } |
1269 | RB_GENERATE_STATIC(__pthread__alltree, __pthread_st, pt_alltree, pthread__cmp) | | 1276 | RB_GENERATE_STATIC(__pthread__alltree, __pthread_st, pt_alltree, pthread__cmp) |
1270 | #endif | | 1277 | #endif |
1271 | | | 1278 | |
1272 | /* Because getenv() wants to use locks. */ | | 1279 | /* Because getenv() wants to use locks. */ |
1273 | char * | | 1280 | char * |
1274 | pthread__getenv(const char *name) | | 1281 | pthread__getenv(const char *name) |
1275 | { | | 1282 | { |
1276 | extern char **environ; | | 1283 | extern char **environ; |
1277 | size_t l_name, offset; | | 1284 | size_t l_name, offset; |
1278 | | | 1285 | |
1279 | l_name = strlen(name); | | 1286 | l_name = strlen(name); |
1280 | for (offset = 0; environ[offset] != NULL; offset++) { | | 1287 | for (offset = 0; environ[offset] != NULL; offset++) { |
1281 | if (strncmp(name, environ[offset], l_name) == 0 && | | 1288 | if (strncmp(name, environ[offset], l_name) == 0 && |
1282 | environ[offset][l_name] == '=') { | | 1289 | environ[offset][l_name] == '=') { |
1283 | return environ[offset] + l_name + 1; | | 1290 | return environ[offset] + l_name + 1; |
1284 | } | | 1291 | } |
1285 | } | | 1292 | } |
1286 | | | 1293 | |
1287 | return NULL; | | 1294 | return NULL; |
1288 | } | | 1295 | } |
1289 | | | 1296 | |
1290 | pthread_mutex_t * | | 1297 | pthread_mutex_t * |
1291 | pthread__hashlock(volatile const void *p) | | 1298 | pthread__hashlock(volatile const void *p) |
1292 | { | | 1299 | { |
1293 | uintptr_t v; | | 1300 | uintptr_t v; |
1294 | | | 1301 | |
1295 | v = (uintptr_t)p; | | 1302 | v = (uintptr_t)p; |
1296 | return &hashlocks[((v >> 9) ^ (v >> 3)) & (NHASHLOCK - 1)].mutex; | | 1303 | return &hashlocks[((v >> 9) ^ (v >> 3)) & (NHASHLOCK - 1)].mutex; |
1297 | } | | 1304 | } |
1298 | | | 1305 | |
1299 | int | | 1306 | int |
1300 | pthread__checkpri(int pri) | | 1307 | pthread__checkpri(int pri) |
1301 | { | | 1308 | { |
1302 | static int havepri; | | 1309 | static int havepri; |
1303 | static long min, max; | | 1310 | static long min, max; |
1304 | | | 1311 | |
1305 | if (!havepri) { | | 1312 | if (!havepri) { |
1306 | min = sysconf(_SC_SCHED_PRI_MIN); | | 1313 | min = sysconf(_SC_SCHED_PRI_MIN); |
1307 | max = sysconf(_SC_SCHED_PRI_MAX); | | 1314 | max = sysconf(_SC_SCHED_PRI_MAX); |
1308 | havepri = 1; | | 1315 | havepri = 1; |
1309 | } | | 1316 | } |
1310 | return (pri < min || pri > max) ? EINVAL : 0; | | 1317 | return (pri < min || pri > max) ? EINVAL : 0; |
1311 | } | | 1318 | } |