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

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: Created 1 year, 3 months ago , Downloaded from: http://bugs.python.org/file9225/threading_local.patch
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
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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)
Antoine Pitrou 2008/08/28 09:29:49 A Py_DECREF(localdict) is needed just before baili
gregory.p.smith 2008/09/02 06:43:30 On 2008/08/28 09:29:49, Antoine Pitrou wrote: > A
209 goto err; 208 goto err;
209 Py_DECREF(localdict);
210 210
211 return (PyObject *)self; 211 return (PyObject *)self;
212 212
213 err: 213 err:
214 Py_DECREF(self); 214 Py_DECREF(self);
215 return NULL; 215 return NULL;
216 } 216 }
217 217
218 static int 218 static int
219 local_traverse(localobject *self, visitproc visit, void *arg) 219 local_traverse(localobject *self, visitproc visit, void *arg)
220 { 220 {
221 Py_VISIT(self->args); 221 Py_VISIT(self->args);
222 Py_VISIT(self->kw); 222 Py_VISIT(self->kw);
223 Py_VISIT(self->dict);
224 return 0; 223 return 0;
225 } 224 }
226 225
227 static int 226 static int
228 local_clear(localobject *self) 227 local_clear(localobject *self)
229 { 228 {
230 Py_CLEAR(self->key); 229 Py_CLEAR(self->key);
231 Py_CLEAR(self->args); 230 Py_CLEAR(self->args);
232 Py_CLEAR(self->kw); 231 Py_CLEAR(self->kw);
233 Py_CLEAR(self->dict);
234 return 0; 232 return 0;
235 } 233 }
236 234
237 static void 235 static void
238 local_dealloc(localobject *self) 236 local_dealloc(localobject *self)
239 { 237 {
240 PyThreadState *tstate; 238 PyThreadState *tstate;
241 if (self->key 239 if (self->key
242 && (tstate = PyThreadState_Get()) 240 && (tstate = PyThreadState_Get())
243 && tstate->interp) { 241 && tstate->interp) {
244 for(tstate = PyInterpreterState_ThreadHead(tstate->interp); 242 for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
245 tstate; 243 tstate;
246 tstate = PyThreadState_Next(tstate)) 244 tstate = PyThreadState_Next(tstate))
247 if (tstate->dict && 245 if (tstate->dict &&
248 PyDict_GetItem(tstate->dict, self->key)) 246 PyDict_GetItem(tstate->dict, self->key))
249 PyDict_DelItem(tstate->dict, self->key); 247 PyDict_DelItem(tstate->dict, self->key);
250 } 248 }
251 249
252 local_clear(self); 250 local_clear(self);
253 Py_TYPE(self)->tp_free((PyObject*)self); 251 Py_TYPE(self)->tp_free((PyObject*)self);
254 } 252 }
255 253
254 /* Return borrowed reference to the local dict */
256 static PyObject * 255 static PyObject *
257 _ldict(localobject *self) 256 _ldict(localobject *self)
258 { 257 {
259 PyObject *tdict, *ldict; 258 PyObject *tdict, *ldict;
260 259
261 tdict = PyThreadState_GetDict(); 260 tdict = PyThreadState_GetDict();
262 if (tdict == NULL) { 261 if (tdict == NULL) {
263 PyErr_SetString(PyExc_SystemError, 262 PyErr_SetString(PyExc_SystemError,
264 "Couldn't get thread-state dictionary"); 263 "Couldn't get thread-state dictionary");
265 return NULL; 264 return NULL;
266 } 265 }
267 266
268 ldict = PyDict_GetItem(tdict, self->key); 267 ldict = PyDict_GetItem(tdict, self->key);
269 if (ldict == NULL) { 268 if (ldict == NULL) {
270 ldict = PyDict_New(); /* we own ldict */ 269 ldict = PyDict_New(); /* we own ldict */
271 270
272 if (ldict == NULL) 271 if (ldict == NULL)
273 return NULL; 272 return NULL;
274 else { 273 else {
275 int i = PyDict_SetItem(tdict, self->key, ldict); 274 int i = PyDict_SetItem(tdict, self->key, ldict);
276 Py_DECREF(ldict); /* now ldict is borrowed */ 275 Py_DECREF(ldict); /* now ldict is borrowed */
277 if (i < 0) 276 if (i < 0)
278 return NULL; 277 return NULL;
279 } 278 }
280
281 Py_CLEAR(self->dict);
282 Py_INCREF(ldict);
283 self->dict = ldict; /* still borrowed */
284 279
285 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && 280 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init &&
286 Py_TYPE(self)->tp_init((PyObject*)self, 281 Py_TYPE(self)->tp_init((PyObject*)self,
287 self->args, self->kw) < 0) { 282 self->args, self->kw) < 0) {
288 /* we need to get rid of ldict from thread so 283 /* we need to get rid of ldict from thread so
289 we create a new one the next time we do an attr 284 we create a new one the next time we do an attr
290 acces */ 285 acces */
291 PyDict_DelItem(tdict, self->key); 286 PyDict_DelItem(tdict, self->key);
292 return NULL; 287 return NULL;
293 } 288 }
294 289
295 }
296 else if (self->dict != ldict) {
297 Py_CLEAR(self->dict);
298 Py_INCREF(ldict);
299 self->dict = ldict;
300 } 290 }
301 291
302 return ldict; 292 return ldict;
303 } 293 }
304 294
305 static int 295 static int
306 local_setattro(localobject *self, PyObject *name, PyObject *v) 296 local_setattro(localobject *self, PyObject *name, PyObject *v)
307 { 297 {
308 » PyObject *ldict; 298 » int res = PyObject_GenericSetAttr((PyObject *)self, name, v);
309 »
310 » ldict = _ldict(self);
311 » if (ldict == NULL)
312 » » return -1;
313 299
314 » return PyObject_GenericSetAttr((PyObject *)self, name, v); 300 » if (res < 0 && PyErr_ExceptionMatches(PyExc_AttributeError)) {
Antoine Pitrou 2008/08/28 09:29:49 Why did you add this fallback? Is it really necess
gregory.p.smith 2008/09/02 06:43:30 On 2008/08/28 09:29:49, Antoine Pitrou wrote: > Wh
301 » » PyObject *ldict = _ldict(self);
302 » » if (ldict == NULL)
303 » » » return -1;
304
305 » » PyErr_Clear();
306
307 » » res = PyDict_SetItem(ldict, name, v);
308 » }
309
310 » return res;
315 } 311 }
316 312
317 static PyObject * 313 static PyObject *
318 local_getdict(localobject *self, void *closure) 314 local_getdict(localobject *self, void *closure)
319 { 315 {
320 » if (self->dict == NULL) { 316 » PyObject *ldict = _ldict(self);
317 » if (ldict == NULL) {
321 PyErr_SetString(PyExc_AttributeError, "__dict__"); 318 PyErr_SetString(PyExc_AttributeError, "__dict__");
322 return NULL; 319 return NULL;
323 } 320 }
324 321
325 » Py_INCREF(self->dict); 322 » Py_INCREF(ldict);
326 » return self->dict; 323 » return ldict;
327 } 324 }
328 325
329 static PyGetSetDef local_getset[] = { 326 static PyGetSetDef local_getset[] = {
330 {"__dict__", (getter)local_getdict, (setter)NULL, 327 {"__dict__", (getter)local_getdict, (setter)NULL,
331 "Local-data dictionary", NULL}, 328 "Local-data dictionary", NULL},
332 {NULL} /* Sentinel */ 329 {NULL} /* Sentinel */
333 }; 330 };
334 331
335 static PyObject *local_getattro(localobject *, PyObject *); 332 static PyObject *local_getattro(localobject *, PyObject *);
336 333
(...skipping 25 matching lines...) Expand all
362 /* tp_weaklistoffset */ 0, 359 /* tp_weaklistoffset */ 0,
363 /* tp_iter */ 0, 360 /* tp_iter */ 0,
364 /* tp_iternext */ 0, 361 /* tp_iternext */ 0,
365 /* tp_methods */ 0, 362 /* tp_methods */ 0,
366 /* tp_members */ 0, 363 /* tp_members */ 0,
367 /* tp_getset */ local_getset, 364 /* tp_getset */ local_getset,
368 /* tp_base */ 0, 365 /* tp_base */ 0,
369 /* tp_dict */ 0, /* internal use */ 366 /* tp_dict */ 0, /* internal use */
370 /* tp_descr_get */ 0, 367 /* tp_descr_get */ 0,
371 /* tp_descr_set */ 0, 368 /* tp_descr_set */ 0,
372 » /* tp_dictoffset */ offsetof(localobject, dict), 369 » /* tp_dictoffset */ 0,
373 /* tp_init */ 0, 370 /* tp_init */ 0,
374 /* tp_alloc */ 0, 371 /* tp_alloc */ 0,
375 /* tp_new */ local_new, 372 /* tp_new */ local_new,
376 /* tp_free */ 0, /* Low-level free-mem routine */ 373 /* tp_free */ 0, /* Low-level free-mem routine */
377 /* tp_is_gc */ 0, /* For PyObject_IS_GC */ 374 /* tp_is_gc */ 0, /* For PyObject_IS_GC */
378 }; 375 };
379 376
380 static PyObject * 377 static PyObject *
381 local_getattro(localobject *self, PyObject *name) 378 local_getattro(localobject *self, PyObject *name)
382 { 379 {
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
709 Py_INCREF(&Locktype); 706 Py_INCREF(&Locktype);
710 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); 707 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
711 708
712 Py_INCREF(&localtype); 709 Py_INCREF(&localtype);
713 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) 710 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0)
714 return; 711 return;
715 712
716 /* Initialize the C thread library */ 713 /* Initialize the C thread library */
717 PyThread_init_thread(); 714 PyThread_init_thread();
718 } 715 }
OLDNEW
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')

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