]> git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_tsd.c
Libc-498.1.1.tar.gz
[apple/libc.git] / pthreads / pthread_tsd.c
1 /*
2 * Copyright (c) 2000-2003, 2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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 */
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
51 * NB: pthread_getspecific() is in a separate assembly file
52 */
53
54 #include "pthread_internals.h"
55
56 static struct
57 {
58 int created; /* Set TRUE if 'create_key' used this slot */
59 void (*destructor)(void *);
60 } _pthread_keys[_INTERNAL_POSIX_THREAD_KEYS_END];
61 static pthread_lock_t tds_lock = LOCK_INITIALIZER;
62
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.
67 * LEFT OVER TILL DYLD changes to using static (1-3) numbers
68 */
69
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
81 /*
82 * Create a new key for thread specific data
83 */
84 int
85 pthread_key_create(pthread_key_t *key,
86 void (*destructor)(void *))
87 {
88 int res, i;
89 LOCK(tds_lock);
90 res = EAGAIN; /* No 'free' keys, return EAGAIN (as per standard) */
91 /* The first slot is reserved for pthread_self() */
92 for (i = __pthread_tsd_start; i < __pthread_tsd_end; i++)
93 {
94 if (_pthread_keys[i].created == FALSE)
95 {
96 _pthread_keys[i].created = TRUE;
97 _pthread_keys[i].destructor = destructor;
98 *key = i;
99 res = 0;
100 break;
101 }
102 }
103 UNLOCK(tds_lock);
104 return (res);
105 }
106
107 /*
108 * Destroy a thread specific data key
109 */
110 int
111 pthread_key_delete(pthread_key_t key)
112 {
113 int res;
114 LOCK(tds_lock);
115 /* The first slot is reserved for pthread_self() */
116 if ((key >= __pthread_tsd_start) && (key < __pthread_tsd_end))
117 {
118 if (_pthread_keys[key].created)
119 {
120 struct _pthread * p;
121
122 _pthread_keys[key].created = FALSE;
123 LOCK(_pthread_list_lock);
124 TAILQ_FOREACH(p, &__pthread_head, plist) {
125 /* It is an 32bit value no lock needed */
126 p->tsd[key] = 0;
127 }
128 UNLOCK(_pthread_list_lock);
129 res = 0;
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 */
151 int
152 pthread_setspecific(pthread_key_t key,
153 const void *value)
154 {
155 int res;
156 pthread_t self;
157 /* The first slot is reserved for pthread_self() */
158 if ((key >= __pthread_tsd_first) && (key < __pthread_tsd_end))
159 {
160 if ((key < __pthread_tsd_start) || _pthread_keys[key].created)
161 {
162 self = pthread_self();
163 self->tsd[key] = (void *) value;
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;
170 } else
171 {
172 res = EINVAL;
173 }
174 } else
175 { /* Invalid key */
176 res = EINVAL;
177 }
178 return (res);
179 }
180
181 /*
182 * Clean up thread specific data as thread 'dies'
183 */
184 void
185 _pthread_tsd_cleanup(pthread_t self)
186 {
187 int i, j;
188 void *param;
189
190 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++)
191 {
192 /* The first slot is reserved for pthread_self() */
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++)
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 }
217 self->max_tsd_key = 0;
218 }
219
220 int
221 pthread_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 */
237 void
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