Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(21)

Side by Side Diff: Modules/threadmodule.c

Issue 3641: thread._local, threading.local Python issue 1868 & 3710 SVN Base: http://svn.python.org/view/*checkout*/python/trunk/
Patch Set: threading_local4 - includes the unit test, fixes the missing error path decref Created 1 year, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 1
2 /* Thread module */ 2 /* Thread module */
3 /* Interface to Sjoerd's portable C thread library */ 3 /* Interface to Sjoerd's portable C thread library */
4 4
5 #include "Python.h" 5 #include "Python.h"
6 6
7 #ifndef WITH_THREAD 7 #ifndef WITH_THREAD
8 #error "Error! The rest of Python is not compiled with thread support." 8 #error "Error! The rest of Python is not compiled with thread support."
9 #error "Rerun configure, adding a --with-threads option." 9 #error "Rerun configure, adding a --with-threads option."
10 #error "Then run `make clean' followed by `make'." 10 #error "Then run `make clean' followed by `make'."
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 157
158 /* Thread-local objects */ 158 /* Thread-local objects */
159 159
160 #include "structmember.h" 160 #include "structmember.h"
161 161
162 typedef struct { 162 typedef struct {
163 PyObject_HEAD 163 PyObject_HEAD
164 PyObject *key; 164 PyObject *key;
165 PyObject *args; 165 PyObject *args;
166 PyObject *kw; 166 PyObject *kw;
167 PyObject *dict;
168 } localobject; 167 } localobject;
169 168
170 static PyObject * 169 static PyObject *
171 local_new(PyTypeObject *type, PyObject *args, PyObject *kw) 170 local_new(PyTypeObject *type, PyObject *args, PyObject *kw)
172 { 171 {
173 localobject *self; 172 localobject *self;
174 PyObject *tdict; 173 PyObject *tdict;
174 PyObject *localdict;
175 175
176 if (type->tp_init == PyBaseObject_Type.tp_init 176 if (type->tp_init == PyBaseObject_Type.tp_init
177 && ((args && PyObject_IsTrue(args)) 177 && ((args && PyObject_IsTrue(args))
178 || (kw && PyObject_IsTrue(kw)))) { 178 || (kw && PyObject_IsTrue(kw)))) {
179 PyErr_SetString(PyExc_TypeError, 179 PyErr_SetString(PyExc_TypeError,
180 "Initialization arguments are not supported"); 180 "Initialization arguments are not supported");
181 return NULL; 181 return NULL;
182 } 182 }
183 183
184 self = (localobject *)type->tp_alloc(type, 0); 184 self = (localobject *)type->tp_alloc(type, 0);
185 if (self == NULL) 185 if (self == NULL)
186 return NULL; 186 return NULL;
187 187
188 Py_XINCREF(args); 188 Py_XINCREF(args);
189 self->args = args; 189 self->args = args;
190 Py_XINCREF(kw); 190 Py_XINCREF(kw);
191 self->kw = kw; 191 self->kw = kw;
192 self->dict = NULL; /* making sure */
193 self->key = PyString_FromFormat("thread.local.%p", self); 192 self->key = PyString_FromFormat("thread.local.%p", self);
194 if (self->key == NULL) 193 if (self->key == NULL)
195 goto err; 194 goto err;
196 195
197 » self->dict = PyDict_New(); 196 » localdict = PyDict_New();
198 » if (self->dict == NULL) 197 » if (localdict == NULL)
199 goto err; 198 goto err;
200 199
201 tdict = PyThreadState_GetDict(); 200 tdict = PyThreadState_GetDict();
202 if (tdict == NULL) { 201 if (tdict == NULL) {
203 PyErr_SetString(PyExc_SystemError, 202 PyErr_SetString(PyExc_SystemError,
204 "Couldn't get thread-state dictionary"); 203 "Couldn't get thread-state dictionary");
205 goto err; 204 goto err;
206 } 205 }
207 206
208 » if (PyDict_SetItem(tdict, self->key, self->dict) < 0) 207 » if (PyDict_SetItem(tdict, self->key, localdict) < 0) {
208 » » Py_DECREF(localdict);
209 goto err; 209 goto err;
210 }
211 Py_DECREF(localdict);
210 212
211 return (PyObject *)self; 213 return (PyObject *)self;
212 214
213 err: 215 err:
214 Py_DECREF(self); 216 Py_DECREF(self);
215 return NULL; 217 return NULL;
216 } 218 }
217 219
218 static int 220 static int
219 local_traverse(localobject *self, visitproc visit, void *arg) 221 local_traverse(localobject *self, visitproc visit, void *arg)
220 { 222 {
221 Py_VISIT(self->args); 223 Py_VISIT(self->args);
222 Py_VISIT(self->kw); 224 Py_VISIT(self->kw);
223 Py_VISIT(self->dict);
224 return 0; 225 return 0;
225 } 226 }
226 227
227 static int 228 static int
228 local_clear(localobject *self) 229 local_clear(localobject *self)
229 { 230 {
230 Py_CLEAR(self->key); 231 Py_CLEAR(self->key);
231 Py_CLEAR(self->args); 232 Py_CLEAR(self->args);
232 Py_CLEAR(self->kw); 233 Py_CLEAR(self->kw);
233 Py_CLEAR(self->dict);
234 return 0; 234 return 0;
235 } 235 }
236 236
237 static void 237 static void
238 local_dealloc(localobject *self) 238 local_dealloc(localobject *self)
239 { 239 {
240 PyThreadState *tstate; 240 PyThreadState *tstate;
241 if (self->key 241 if (self->key
242 && (tstate = PyThreadState_Get()) 242 && (tstate = PyThreadState_Get())
243 && tstate->interp) { 243 && tstate->interp) {
244 for(tstate = PyInterpreterState_ThreadHead(tstate->interp); 244 for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
245 tstate; 245 tstate;
246 tstate = PyThreadState_Next(tstate)) 246 tstate = PyThreadState_Next(tstate))
247 if (tstate->dict && 247 if (tstate->dict &&
248 PyDict_GetItem(tstate->dict, self->key)) 248 PyDict_GetItem(tstate->dict, self->key))
249 PyDict_DelItem(tstate->dict, self->key); 249 PyDict_DelItem(tstate->dict, self->key);
250 } 250 }
251 251
252 local_clear(self); 252 local_clear(self);
253 Py_TYPE(self)->tp_free((PyObject*)self); 253 Py_TYPE(self)->tp_free((PyObject*)self);
254 } 254 }
255 255
256 /* Return borrowed reference to the local dict */
256 static PyObject * 257 static PyObject *
257 _ldict(localobject *self) 258 _ldict(localobject *self)
258 { 259 {
259 PyObject *tdict, *ldict; 260 PyObject *tdict, *ldict;
260 261
261 tdict = PyThreadState_GetDict(); 262 tdict = PyThreadState_GetDict();
262 if (tdict == NULL) { 263 if (tdict == NULL) {
263 PyErr_SetString(PyExc_SystemError, 264 PyErr_SetString(PyExc_SystemError,
264 "Couldn't get thread-state dictionary"); 265 "Couldn't get thread-state dictionary");
265 return NULL; 266 return NULL;
266 } 267 }
267 268
268 ldict = PyDict_GetItem(tdict, self->key); 269 ldict = PyDict_GetItem(tdict, self->key);
269 if (ldict == NULL) { 270 if (ldict == NULL) {
270 ldict = PyDict_New(); /* we own ldict */ 271 ldict = PyDict_New(); /* we own ldict */
271 272
272 if (ldict == NULL) 273 if (ldict == NULL)
273 return NULL; 274 return NULL;
274 else { 275 else {
275 int i = PyDict_SetItem(tdict, self->key, ldict); 276 int i = PyDict_SetItem(tdict, self->key, ldict);
276 Py_DECREF(ldict); /* now ldict is borrowed */ 277 Py_DECREF(ldict); /* now ldict is borrowed */
277 if (i < 0) 278 if (i < 0)
278 return NULL; 279 return NULL;
279 } 280 }
280
281 Py_CLEAR(self->dict);
282 Py_INCREF(ldict);
283 self->dict = ldict; /* still borrowed */
284 281
285 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && 282 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init &&
286 Py_TYPE(self)->tp_init((PyObject*)self, 283 Py_TYPE(self)->tp_init((PyObject*)self,
287 self->args, self->kw) < 0) { 284 self->args, self->kw) < 0) {
288 /* we need to get rid of ldict from thread so 285 /* we need to get rid of ldict from thread so
289 we create a new one the next time we do an attr 286 we create a new one the next time we do an attr
290 acces */ 287 acces */
291 PyDict_DelItem(tdict, self->key); 288 PyDict_DelItem(tdict, self->key);
292 return NULL; 289 return NULL;
293 } 290 }
294 291
295 }
296
297 /* The call to tp_init above may have caused another thread to run.
298 Install our ldict again. */
299 if (self->dict != ldict) {
300 Py_CLEAR(self->dict);
301 Py_INCREF(ldict);
302 self->dict = ldict;
303 } 292 }
304 293
305 return ldict; 294 return ldict;
306 } 295 }
307 296
308 static int 297 static int
309 local_setattro(localobject *self, PyObject *name, PyObject *v) 298 local_setattro(localobject *self, PyObject *name, PyObject *v)
310 { 299 {
311 » PyObject *ldict; 300 » PyObject *ldict = _ldict(self);
312 »
313 » ldict = _ldict(self);
314 if (ldict == NULL) 301 if (ldict == NULL)
315 return -1; 302 return -1;
316 303
317 » return PyObject_GenericSetAttr((PyObject *)self, name, v); 304 » if (v != NULL) {
305 » » return PyDict_SetItem(ldict, name, v);
306 » } else {
307 » » int res;
308 » » res = PyDict_DelItem(ldict, name);
309 » » if ((res < 0) && PyErr_ExceptionMatches(PyExc_KeyError)) {
310 » » » PyErr_SetObject(PyExc_AttributeError, name);
311 » » }
312 » » return res;
313 » }
318 } 314 }
319 315
320 static PyObject * 316 static PyObject *
321 local_getdict(localobject *self, void *closure) 317 local_getdict(localobject *self, void *closure)
322 { 318 {
323 » if (self->dict == NULL) { 319 » PyObject *ldict = _ldict(self);
320 » if (ldict == NULL) {
324 PyErr_SetString(PyExc_AttributeError, "__dict__"); 321 PyErr_SetString(PyExc_AttributeError, "__dict__");
325 return NULL; 322 return NULL;
326 } 323 }
327 324
328 » Py_INCREF(self->dict); 325 » Py_INCREF(ldict);
329 » return self->dict; 326 » return ldict;
330 } 327 }
331 328
332 static PyGetSetDef local_getset[] = { 329 static PyGetSetDef local_getset[] = {
333 {"__dict__", (getter)local_getdict, (setter)NULL, 330 {"__dict__", (getter)local_getdict, (setter)NULL,
334 "Local-data dictionary", NULL}, 331 "Local-data dictionary", NULL},
335 {NULL} /* Sentinel */ 332 {NULL} /* Sentinel */
336 }; 333 };
337 334
338 static PyObject *local_getattro(localobject *, PyObject *); 335 static PyObject *local_getattro(localobject *, PyObject *);
339 336
(...skipping 25 matching lines...) Expand all
365 /* tp_weaklistoffset */ 0, 362 /* tp_weaklistoffset */ 0,
366 /* tp_iter */ 0, 363 /* tp_iter */ 0,
367 /* tp_iternext */ 0, 364 /* tp_iternext */ 0,
368 /* tp_methods */ 0, 365 /* tp_methods */ 0,
369 /* tp_members */ 0, 366 /* tp_members */ 0,
370 /* tp_getset */ local_getset, 367 /* tp_getset */ local_getset,
371 /* tp_base */ 0, 368 /* tp_base */ 0,
372 /* tp_dict */ 0, /* internal use */ 369 /* tp_dict */ 0, /* internal use */
373 /* tp_descr_get */ 0, 370 /* tp_descr_get */ 0,
374 /* tp_descr_set */ 0, 371 /* tp_descr_set */ 0,
375 » /* tp_dictoffset */ offsetof(localobject, dict), 372 » /* tp_dictoffset */ 0,
376 /* tp_init */ 0, 373 /* tp_init */ 0,
377 /* tp_alloc */ 0, 374 /* tp_alloc */ 0,
378 /* tp_new */ local_new, 375 /* tp_new */ local_new,
379 /* tp_free */ 0, /* Low-level free-mem routine */ 376 /* tp_free */ 0, /* Low-level free-mem routine */
380 /* tp_is_gc */ 0, /* For PyObject_IS_GC */ 377 /* tp_is_gc */ 0, /* For PyObject_IS_GC */
381 }; 378 };
382 379
383 static PyObject * 380 static PyObject *
384 local_getattro(localobject *self, PyObject *name) 381 local_getattro(localobject *self, PyObject *name)
385 { 382 {
386 PyObject *ldict, *value; 383 PyObject *ldict, *value;
387 384
388 ldict = _ldict(self); 385 ldict = _ldict(self);
389 if (ldict == NULL) 386 if (ldict == NULL)
390 return NULL; 387 return NULL;
391
392 if (Py_TYPE(self) != &localtype)
393 /* use generic lookup for subtypes */
394 return PyObject_GenericGetAttr((PyObject *)self, name);
395 388
396 /* Optimization: just look in dict ourselves */ 389 /* Optimization: just look in dict ourselves */
397 value = PyDict_GetItem(ldict, name); 390 value = PyDict_GetItem(ldict, name);
398 if (value == NULL) 391 if (value == NULL)
399 /* Fall back on generic to get __class__ and __dict__ */ 392 /* Fall back on generic to get __class__ and __dict__ */
400 return PyObject_GenericGetAttr((PyObject *)self, name); 393 return PyObject_GenericGetAttr((PyObject *)self, name);
401 394
402 Py_INCREF(value); 395 Py_INCREF(value);
403 return value; 396 return value;
404 } 397 }
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
712 Py_INCREF(&Locktype); 705 Py_INCREF(&Locktype);
713 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); 706 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
714 707
715 Py_INCREF(&localtype); 708 Py_INCREF(&localtype);
716 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) 709 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0)
717 return; 710 return;
718 711
719 /* Initialize the C thread library */ 712 /* Initialize the C thread library */
720 PyThread_init_thread(); 713 PyThread_init_thread();
721 } 714 }
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld r483