]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_tsd.c
Libc-498.1.5.tar.gz
[apple/libc.git] / pthreads / pthread_tsd.c
CommitLineData
9385eb3d 1/*
224c7076 2 * Copyright (c) 2000-2003, 2007 Apple Inc. All rights reserved.
9385eb3d
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9385eb3d
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
e9ce8d39
A
23/*
24 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
25 * All Rights Reserved
26 *
27 * Permission to use, copy, modify, and distribute this software and
28 * its documentation for any purpose and without fee is hereby granted,
29 * provided that the above copyright notice appears in all copies and
30 * that both the copyright notice and this permission notice appear in
31 * supporting documentation.
32 *
33 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
34 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
36 *
37 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
39 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
40 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
41 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 *
43 */
44/*
45 * MkLinux
46 */
47
48/*
49 * POSIX Pthread Library
50 * Thread Specific Data support
9385eb3d 51 * NB: pthread_getspecific() is in a separate assembly file
e9ce8d39
A
52 */
53
54#include "pthread_internals.h"
55
56static struct
57{
58 int created; /* Set TRUE if 'create_key' used this slot */
59 void (*destructor)(void *);
224c7076 60} _pthread_keys[_INTERNAL_POSIX_THREAD_KEYS_END];
e9ce8d39 61static pthread_lock_t tds_lock = LOCK_INITIALIZER;
224c7076 62
a5cd208c
A
63/*
64 * Partition _pthread_keys in a lower part that dyld can use, and an upper
65 * part for libSystem. The libSystem part starts at __pthread_tsd_first = 4.
66 * dyld will set this value to 1.
224c7076 67 * LEFT OVER TILL DYLD changes to using static (1-3) numbers
a5cd208c 68 */
e9ce8d39 69
224c7076
A
70#ifdef DYLD_STATIC_LIBC_BUILD
71__private_extern__ int __pthread_tsd_first = 1;
72__private_extern__ int __pthread_tsd_start = 5;
73__private_extern__ int __pthread_tsd_end = 10;
74__private_extern__ int __pthread_tsd_max = 10;
75#else
76__private_extern__ int __pthread_tsd_first = 10;
77__private_extern__ int __pthread_tsd_start = _INTERNAL_POSIX_THREAD_KEYS_MAX;
78__private_extern__ int __pthread_tsd_end = _INTERNAL_POSIX_THREAD_KEYS_END;
79__private_extern__ int __pthread_tsd_max = 10;
80#endif
e9ce8d39
A
81/*
82 * Create a new key for thread specific data
83 */
84int
85pthread_key_create(pthread_key_t *key,
86 void (*destructor)(void *))
87{
88 int res, i;
89 LOCK(tds_lock);
224c7076 90 res = EAGAIN; /* No 'free' keys, return EAGAIN (as per standard) */
9385eb3d 91 /* The first slot is reserved for pthread_self() */
224c7076 92 for (i = __pthread_tsd_start; i < __pthread_tsd_end; i++)
e9ce8d39
A
93 {
94 if (_pthread_keys[i].created == FALSE)
95 {
96 _pthread_keys[i].created = TRUE;
97 _pthread_keys[i].destructor = destructor;
9385eb3d 98 *key = i;
224c7076 99 res = 0;
e9ce8d39
A
100 break;
101 }
102 }
103 UNLOCK(tds_lock);
104 return (res);
105}
106
107/*
108 * Destroy a thread specific data key
109 */
110int
111pthread_key_delete(pthread_key_t key)
112{
113 int res;
114 LOCK(tds_lock);
9385eb3d 115 /* The first slot is reserved for pthread_self() */
224c7076 116 if ((key >= __pthread_tsd_start) && (key < __pthread_tsd_end))
e9ce8d39 117 {
9385eb3d 118 if (_pthread_keys[key].created)
e9ce8d39 119 {
9385eb3d
A
120 struct _pthread * p;
121
122 _pthread_keys[key].created = FALSE;
123 LOCK(_pthread_list_lock);
224c7076 124 TAILQ_FOREACH(p, &__pthread_head, plist) {
9385eb3d
A
125 /* It is an 32bit value no lock needed */
126 p->tsd[key] = 0;
127 }
128 UNLOCK(_pthread_list_lock);
224c7076 129 res = 0;
e9ce8d39
A
130 } else
131 {
132 res = EINVAL;
133 }
134 } else
135 { /* Invalid key */
136 res = EINVAL;
137 }
138 UNLOCK(tds_lock);
139 return (res);
140}
141
142/*
143 * Set the thread private value for a given key.
144 * We do not take the spinlock for this or pthread_getspecific.
145 * The assignment to self->tsd[] is thread-safe because we never
146 * refer to the tsd[] of a thread other than pthread_self().
147 * The reference to _pthread_keys[...].created could race with a
148 * pthread_key_delete() but in this case the behaviour is allowed
149 * to be undefined.
150 */
151int
152pthread_setspecific(pthread_key_t key,
153 const void *value)
154{
155 int res;
156 pthread_t self;
9385eb3d 157 /* The first slot is reserved for pthread_self() */
224c7076 158 if ((key >= __pthread_tsd_first) && (key < __pthread_tsd_end))
e9ce8d39 159 {
224c7076 160 if ((key < __pthread_tsd_start) || _pthread_keys[key].created)
e9ce8d39
A
161 {
162 self = pthread_self();
9385eb3d 163 self->tsd[key] = (void *) value;
224c7076
A
164 res = 0;
165 if ((key < __pthread_tsd_start) && (_pthread_keys[key].created == FALSE))
166 _pthread_keys[key].created = TRUE;
167
168 if (key > self->max_tsd_key)
169 self->max_tsd_key = key;
e9ce8d39
A
170 } else
171 {
172 res = EINVAL;
173 }
174 } else
175 { /* Invalid key */
176 res = EINVAL;
177 }
178 return (res);
179}
180
e9ce8d39
A
181/*
182 * Clean up thread specific data as thread 'dies'
183 */
184void
185_pthread_tsd_cleanup(pthread_t self)
186{
187 int i, j;
188 void *param;
224c7076 189
e9ce8d39
A
190 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++)
191 {
9385eb3d 192 /* The first slot is reserved for pthread_self() */
224c7076
A
193
194 for (i = __pthread_tsd_first; i <= __pthread_tsd_max; i++)
195 {
196 if (_pthread_keys[i].created && (param = self->tsd[i]))
197 {
198 self->tsd[i] = (void *)NULL;
199 if (_pthread_keys[i].destructor)
200 {
201 (_pthread_keys[i].destructor)(param);
202 }
203 }
204 }
205 for (i = __pthread_tsd_start; i <= self->max_tsd_key; i++)
e9ce8d39
A
206 {
207 if (_pthread_keys[i].created && (param = self->tsd[i]))
208 {
209 self->tsd[i] = (void *)NULL;
210 if (_pthread_keys[i].destructor)
211 {
212 (_pthread_keys[i].destructor)(param);
213 }
214 }
215 }
216 }
224c7076 217 self->max_tsd_key = 0;
e9ce8d39 218}
224c7076
A
219
220int
221pthread_key_init_np(int key, void (*destructor)(void *))
222{
223 if ((key >= __pthread_tsd_first) && (key < __pthread_tsd_start)) {
224 LOCK(tds_lock);
225 _pthread_keys[key].created = TRUE;
226 _pthread_keys[key].destructor = destructor;
227
228 if (key > __pthread_tsd_max)
229 __pthread_tsd_max = key;
230 UNLOCK(tds_lock);
231 return (0);
232 } else
233 return(EINVAL);
234}
235
236/* we need this till the switchover happens for the dyld. It get 1- 10 slot */
237void
238_pthread_keys_init()
239{
240 if (__pthread_tsd_first == 1) {
241 __pthread_tsd_start = 5;
242 __pthread_tsd_end = 10;
243 __pthread_tsd_max = 10;
244 }
245
246}
247