]> git.saurik.com Git - apple/libc.git/blob - pthreads.subproj/pthread_tsd.c
f8cfb6b87c55a98a723e8c3350dd322797687d9c
[apple/libc.git] / pthreads.subproj / pthread_tsd.c
1 /*
2 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
3 * All Rights Reserved
4 *
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both the copyright notice and this permission notice appear in
9 * supporting documentation.
10 *
11 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 */
22 /*
23 * MkLinux
24 */
25
26 /*
27 * POSIX Pthread Library
28 * Thread Specific Data support
29 */
30
31 #include "pthread_internals.h"
32
33 static struct
34 {
35 int created; /* Set TRUE if 'create_key' used this slot */
36 void (*destructor)(void *);
37 } _pthread_keys[_POSIX_THREAD_KEYS_MAX];
38 static pthread_lock_t tds_lock = LOCK_INITIALIZER;
39
40 /*
41 * Create a new key for thread specific data
42 */
43 int
44 pthread_key_create(pthread_key_t *key,
45 void (*destructor)(void *))
46 {
47 int res, i;
48 LOCK(tds_lock);
49 res = ENOMEM; /* No 'free' keys */
50 for (i = 0; i < _POSIX_THREAD_KEYS_MAX; i++)
51 {
52 if (_pthread_keys[i].created == FALSE)
53 {
54 _pthread_keys[i].created = TRUE;
55 _pthread_keys[i].destructor = destructor;
56 *key = i+1;
57 res = ESUCCESS;
58 break;
59 }
60 }
61 UNLOCK(tds_lock);
62 return (res);
63 }
64
65 /*
66 * Destroy a thread specific data key
67 */
68 int
69 pthread_key_delete(pthread_key_t key)
70 {
71 int res;
72 LOCK(tds_lock);
73 if ((key >= 1) && (key <= _POSIX_THREAD_KEYS_MAX))
74 {
75 if (_pthread_keys[key-1].created)
76 {
77 _pthread_keys[key-1].created = FALSE;
78 res = ESUCCESS;
79 } else
80 {
81 res = EINVAL;
82 }
83 } else
84 { /* Invalid key */
85 res = EINVAL;
86 }
87 UNLOCK(tds_lock);
88 return (res);
89 }
90
91 /*
92 * Set the thread private value for a given key.
93 * We do not take the spinlock for this or pthread_getspecific.
94 * The assignment to self->tsd[] is thread-safe because we never
95 * refer to the tsd[] of a thread other than pthread_self().
96 * The reference to _pthread_keys[...].created could race with a
97 * pthread_key_delete() but in this case the behaviour is allowed
98 * to be undefined.
99 */
100 int
101 pthread_setspecific(pthread_key_t key,
102 const void *value)
103 {
104 int res;
105 pthread_t self;
106 if ((key >= 1) && (key <= _POSIX_THREAD_KEYS_MAX))
107 {
108 if (_pthread_keys[key-1].created)
109 {
110 self = pthread_self();
111 self->tsd[key-1] = (void *) value;
112 res = ESUCCESS;
113 } else
114 {
115 res = EINVAL;
116 }
117 } else
118 { /* Invalid key */
119 res = EINVAL;
120 }
121 return (res);
122 }
123
124 /*
125 * Fetch the thread private value for a given key.
126 * This is potentially a very heavily-used operation so we do only
127 * a minimum of checks.
128 */
129 void *
130 pthread_getspecific(pthread_key_t key)
131 {
132 pthread_t self;
133 void *res;
134 if ((key >= 1) && (key <= _POSIX_THREAD_KEYS_MAX))
135 {
136 self = pthread_self();
137 res = self->tsd[key-1];
138 } else
139 { /* Invalid key - no error, just NULL */
140 res = (void *)NULL;
141 }
142 return (res);
143 }
144
145 /*
146 * Clean up thread specific data as thread 'dies'
147 */
148 void
149 _pthread_tsd_cleanup(pthread_t self)
150 {
151 int i, j;
152 void *param;
153 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++)
154 {
155 for (i = 0; i < _POSIX_THREAD_KEYS_MAX; i++)
156 {
157 if (_pthread_keys[i].created && (param = self->tsd[i]))
158 {
159 self->tsd[i] = (void *)NULL;
160 if (_pthread_keys[i].destructor)
161 {
162 (_pthread_keys[i].destructor)(param);
163 }
164 }
165 }
166 }
167 }