Skip to content

Commit dfb3e4c

Browse files
author
tim_one
committed
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. git-svn-id: http://svn.python.org/projects/python/trunk@37569 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent b992ff1 commit dfb3e4c

1 file changed

Lines changed: 84 additions & 6 deletions

File tree

Python/thread.c

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,26 +142,80 @@ void PyThread_init_thread(void)
142142
This code stolen from "thread_sgi.h", where it was the only
143143
implementation of an existing Python TLS API.
144144
*/
145-
/*
146-
* Per-thread data ("key") support.
147-
*/
145+
/* ------------------------------------------------------------------------
146+
Per-thread data ("key") support.
147+
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.
148163
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+
*/
149185
struct key {
186+
/* Next record in the list, or NULL if this is the last record. */
150187
struct key *next;
188+
189+
/* The thread id, according to PyThread_get_thread_ident(). */
151190
long id;
191+
192+
/* The key and its associated value. */
152193
int key;
153194
void *value;
154195
};
155196

156197
static struct key *keyhead = NULL;
157-
static int nkeys = 0;
158198
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+
*/
160213
static struct key *
161214
find_key(int key, void *value)
162215
{
163216
struct key *p;
164217
long id = PyThread_get_thread_ident();
218+
165219
for (p = keyhead; p != NULL; p = p->next) {
166220
if (p->id == id && p->key == key)
167221
return p;
@@ -181,18 +235,27 @@ find_key(int key, void *value)
181235
return p;
182236
}
183237

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+
*/
184242
int
185243
PyThread_create_key(void)
186244
{
245+
/* All parts of this function are wrong if it's called by multiple
246+
* threads simultaneously.
247+
*/
187248
if (keymutex == NULL)
188249
keymutex = PyThread_allocate_lock();
189250
return ++nkeys;
190251
}
191252

253+
/* Forget the associations for key across *all* threads. */
192254
void
193255
PyThread_delete_key(int key)
194256
{
195257
struct key *p, **q;
258+
196259
PyThread_acquire_lock(keymutex, 1);
197260
q = &keyhead;
198261
while ((p = *q) != NULL) {
@@ -207,31 +270,46 @@ PyThread_delete_key(int key)
207270
PyThread_release_lock(keymutex);
208271
}
209272

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+
*/
210279
int
211280
PyThread_set_key_value(int key, void *value)
212281
{
213-
struct key *p = find_key(key, value);
282+
struct key *p;
283+
284+
assert(value != NULL);
285+
p = find_key(key, value);
214286
if (p == NULL)
215287
return -1;
216288
else
217289
return 0;
218290
}
219291

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+
*/
220295
void *
221296
PyThread_get_key_value(int key)
222297
{
223298
struct key *p = find_key(key, NULL);
299+
224300
if (p == NULL)
225301
return NULL;
226302
else
227303
return p->value;
228304
}
229305

306+
/* Forget the current thread's association for key, if any. */
230307
void
231308
PyThread_delete_key_value(int key)
232309
{
233310
long id = PyThread_get_thread_ident();
234311
struct key *p, **q;
312+
235313
PyThread_acquire_lock(keymutex, 1);
236314
q = &keyhead;
237315
while ((p = *q) != NULL) {

0 commit comments

Comments
 (0)