Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fda787f

Browse files
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.
1 parent f267b62 commit fda787f

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)