comparison Python/thread.c @ 33705:891042c94aed legacy-trunk

Document the results of painful reverse-engineering of the "portable TLS" code. PyThread_set_key_value(): It's clear that this code assumes the passed-in value isn't NULL, so document that it must not be, and assert that it isn't. It remains unclear whether existing callers want the odd semantics actually implemented by this function.
author Tim Peters <tim.peters@gmail.com>
date Sat, 09 Oct 2004 22:33:09 +0000
parents 0c26db381673
children baa2653f7a76
comparison
equal deleted inserted replaced
33704:295bd8c55a78 33705:891042c94aed
140 TLS implementation, provide our own. 140 TLS implementation, provide our own.
141 141
142 This code stolen from "thread_sgi.h", where it was the only 142 This code stolen from "thread_sgi.h", where it was the only
143 implementation of an existing Python TLS API. 143 implementation of an existing Python TLS API.
144 */ 144 */
145 /* 145 /* ------------------------------------------------------------------------
146 * Per-thread data ("key") support. 146 Per-thread data ("key") support.
147 */ 147
148 148 Use PyThread_create_key() to create a new key. This is typically shared
149 across threads.
150
151 Use PyThread_set_key_value(thekey, value) to associate void* value with
152 thekey in the current thread. Each thread has a distinct mapping of thekey
153 to a void* value. Caution: if the current thread already has a mapping
154 for thekey, value is ignored.
155
156 Use PyThread_get_key_value(thekey) to retrieve the void* value associated
157 with thekey in the current thread. This returns NULL if no value is
158 associated with thekey in the current thread.
159
160 Use PyThread_delete_key_value(thekey) to forget the current thread's associated
161 value for thekey. PyThread_delete_key(thekey) forgets the values associated
162 with thekey across *all* threads.
163
164 While some of these functions have error-return values, none set any
165 Python exception.
166
167 None of the functions does memory management on behalf of the void* values.
168 You need to allocate and deallocate them yourself. If the void* values
169 happen to be PyObject*, these functions don't do refcount operations on
170 them either.
171
172 The GIL does not need to be held when calling these functions; they supply
173 their own locking. This isn't true of PyThread_create_key(), though (see
174 next paragraph).
175
176 There's a hidden assumption that PyThread_create_key() will be called before
177 any of the other functions are called. There's also a hidden assumption
178 that calls to PyThread_create_key() are serialized externally.
179 ------------------------------------------------------------------------ */
180
181 /* A singly-linked list of struct key objects remembers all the key->value
182 * associations. File static keyhead heads the list. keymutex is used
183 * to enforce exclusion internally.
184 */
149 struct key { 185 struct key {
186 /* Next record in the list, or NULL if this is the last record. */
150 struct key *next; 187 struct key *next;
188
189 /* The thread id, according to PyThread_get_thread_ident(). */
151 long id; 190 long id;
191
192 /* The key and its associated value. */
152 int key; 193 int key;
153 void *value; 194 void *value;
154 }; 195 };
155 196
156 static struct key *keyhead = NULL; 197 static struct key *keyhead = NULL;
157 static int nkeys = 0;
158 static PyThread_type_lock keymutex = NULL; 198 static PyThread_type_lock keymutex = NULL;
159 199 static int nkeys = 0; /* PyThread_create_key() hands out nkeys+1 next */
200
201 /* Internal helper.
202 * If the current thread has a mapping for key, the appropriate struct key*
203 * is returned. NB: value is ignored in this case!
204 * If there is no mapping for key in the current thread, then:
205 * If value is NULL, NULL is returned.
206 * Else a mapping of key to value is created for the current thread,
207 * and a pointer to a new struct key* is returned; except that if
208 * malloc() can't find room for a new struct key*, NULL is returned.
209 * So when value==NULL, this acts like a pure lookup routine, and when
210 * value!=NULL, this acts like dict.setdefault(), returning an existing
211 * mapping if one exists, else creating a new mapping.
212 */
160 static struct key * 213 static struct key *
161 find_key(int key, void *value) 214 find_key(int key, void *value)
162 { 215 {
163 struct key *p; 216 struct key *p;
164 long id = PyThread_get_thread_ident(); 217 long id = PyThread_get_thread_ident();
218
165 for (p = keyhead; p != NULL; p = p->next) { 219 for (p = keyhead; p != NULL; p = p->next) {
166 if (p->id == id && p->key == key) 220 if (p->id == id && p->key == key)
167 return p; 221 return p;
168 } 222 }
169 if (value == NULL) 223 if (value == NULL)
179 PyThread_release_lock(keymutex); 233 PyThread_release_lock(keymutex);
180 } 234 }
181 return p; 235 return p;
182 } 236 }
183 237
238 /* Return a new key. This must be called before any other functions in
239 * this family, and callers must arrange to serialize calls to this
240 * function. No violations are detected.
241 */
184 int 242 int
185 PyThread_create_key(void) 243 PyThread_create_key(void)
186 { 244 {
245 /* All parts of this function are wrong if it's called by multiple
246 * threads simultaneously.
247 */
187 if (keymutex == NULL) 248 if (keymutex == NULL)
188 keymutex = PyThread_allocate_lock(); 249 keymutex = PyThread_allocate_lock();
189 return ++nkeys; 250 return ++nkeys;
190 } 251 }
191 252
253 /* Forget the associations for key across *all* threads. */
192 void 254 void
193 PyThread_delete_key(int key) 255 PyThread_delete_key(int key)
194 { 256 {
195 struct key *p, **q; 257 struct key *p, **q;
258
196 PyThread_acquire_lock(keymutex, 1); 259 PyThread_acquire_lock(keymutex, 1);
197 q = &keyhead; 260 q = &keyhead;
198 while ((p = *q) != NULL) { 261 while ((p = *q) != NULL) {
199 if (p->key == key) { 262 if (p->key == key) {
200 *q = p->next; 263 *q = p->next;
205 q = &p->next; 268 q = &p->next;
206 } 269 }
207 PyThread_release_lock(keymutex); 270 PyThread_release_lock(keymutex);
208 } 271 }
209 272
273 /* Confusing: If the current thread has an association for key,
274 * value is ignored, and 0 is returned. Else an attempt is made to create
275 * an association of key to value for the current thread. 0 is returned
276 * if that succeeds, but -1 is returned if there's not enough memory
277 * to create the association. value must not be NULL.
278 */
210 int 279 int
211 PyThread_set_key_value(int key, void *value) 280 PyThread_set_key_value(int key, void *value)
212 { 281 {
213 struct key *p = find_key(key, value); 282 struct key *p;
283
284 assert(value != NULL);
285 p = find_key(key, value);
214 if (p == NULL) 286 if (p == NULL)
215 return -1; 287 return -1;
216 else 288 else
217 return 0; 289 return 0;
218 } 290 }
219 291
292 /* Retrieve the value associated with key in the current thread, or NULL
293 * if the current thread doesn't have an association for key.
294 */
220 void * 295 void *
221 PyThread_get_key_value(int key) 296 PyThread_get_key_value(int key)
222 { 297 {
223 struct key *p = find_key(key, NULL); 298 struct key *p = find_key(key, NULL);
299
224 if (p == NULL) 300 if (p == NULL)
225 return NULL; 301 return NULL;
226 else 302 else
227 return p->value; 303 return p->value;
228 } 304 }
229 305
306 /* Forget the current thread's association for key, if any. */
230 void 307 void
231 PyThread_delete_key_value(int key) 308 PyThread_delete_key_value(int key)
232 { 309 {
233 long id = PyThread_get_thread_ident(); 310 long id = PyThread_get_thread_ident();
234 struct key *p, **q; 311 struct key *p, **q;
312
235 PyThread_acquire_lock(keymutex, 1); 313 PyThread_acquire_lock(keymutex, 1);
236 q = &keyhead; 314 q = &keyhead;
237 while ((p = *q) != NULL) { 315 while ((p = *q) != NULL) {
238 if (p->key == key && p->id == id) { 316 if (p->key == key && p->id == id) {
239 *q = p->next; 317 *q = p->next;