Mercurial > cpython-lru_cache-weakref
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; |
