Index: Python/thread.c =================================================================== --- Python/thread.c (revision 84551) +++ Python/thread.c (working copy) @@ -259,7 +259,7 @@ prev_p = NULL; for (p = keyhead; p != NULL; p = p->next) { if (p->id == id && p->key == key) - goto Done; + break; /* Sanity check. These states should never happen but if * they do we must abort. Otherwise we'll end up spinning in * in a tight loop with the lock held. A similar check is done @@ -270,20 +270,24 @@ if (p->next == keyhead) Py_FatalError("tls find_key: circular list(!)"); } - if (value == NULL) { - assert(p == NULL); - goto Done; - } + PyThread_release_lock(keymutex); + if (p != NULL || value == NULL) + return p; + + /* Allocation operations are done without holding the lock, + * since custom implementations of malloc may actually use this TLS + * themselves. + */ p = (struct key *)malloc(sizeof(struct key)); if (p != NULL) { p->id = id; p->key = key; p->value = value; + PyThread_acquire_lock(keymutex, 1); p->next = keyhead; keyhead = p; + PyThread_release_lock(keymutex); } - Done: - PyThread_release_lock(keymutex); return p; } @@ -306,20 +310,26 @@ void PyThread_delete_key(int key) { - struct key *p, **q; + struct key *p, **q, *to_free = NULL; PyThread_acquire_lock(keymutex, 1); q = &keyhead; while ((p = *q) != NULL) { if (p->key == key) { *q = p->next; - free((void *)p); + p->next = to_free; + to_free = p; /* NB This does *not* free p->value! */ } else q = &p->next; } PyThread_release_lock(keymutex); + for(p = to_free; p != NULL; ) { + struct key *tmp = p->next; + free((void*)p); + p = tmp; + } } /* Confusing: If the current thread has an association for key, @@ -360,14 +370,14 @@ PyThread_delete_key_value(int key) { long id = PyThread_get_thread_ident(); - struct key *p, **q; + struct key *p, **q, *to_free = NULL; PyThread_acquire_lock(keymutex, 1); q = &keyhead; while ((p = *q) != NULL) { if (p->key == key && p->id == id) { *q = p->next; - free((void *)p); + to_free = NULL; /* NB This does *not* free p->value! */ break; } @@ -375,6 +385,8 @@ q = &p->next; } PyThread_release_lock(keymutex); + if (to_free != NULL) + free((void*)to_free); } /* Forget everything not associated with the current thread id.