# HG changeset patch # User krisvale # Date 1332253329 0 # Node ID b4d39078c708b1ca988113af084508d9bbc18ff9 # Parent 0554183066b50f3c137f7e11812dba3d67a6179c [mq]: 2012-03-20_13-59-52_r75779+.diff diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -220,7 +220,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 @@ -231,20 +231,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 to query e.g. thread ID. + * Only this thread will ever allocate this id/key combination so there is no race. + */ 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; } @@ -267,20 +271,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); - /* NB This does *not* free p->value! */ + p->next = to_free; + to_free = p; } else q = &p->next; } PyThread_release_lock(keymutex); + for(p = to_free; p != NULL; ) { + struct key *tmp = p->next; + free((void*)p); + /* NB This does *not* free p->value! */ + p = tmp; + } } /* Confusing: If the current thread has an association for key, @@ -321,21 +331,23 @@ 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); - /* NB This does *not* free p->value! */ + to_free = p; break; } else q = &p->next; } PyThread_release_lock(keymutex); + if (to_free != NULL) + free((void*)to_free); + /* NB This does *not* free p->value! */ } /* Forget everything not associated with the current thread id.