@@ -155,6 +155,273 @@ static PyTypeObject Locktype = {
155
155
lock_methods , /*tp_methods*/
156
156
};
157
157
158
+ /* Recursive lock objects */
159
+
160
+ typedef struct {
161
+ PyObject_HEAD
162
+ PyThread_type_lock rlock_lock ;
163
+ long rlock_owner ;
164
+ unsigned long rlock_count ;
165
+ PyObject * in_weakreflist ;
166
+ } rlockobject ;
167
+
168
+ static void
169
+ rlock_dealloc (rlockobject * self )
170
+ {
171
+ assert (self -> rlock_lock );
172
+ if (self -> in_weakreflist != NULL )
173
+ PyObject_ClearWeakRefs ((PyObject * ) self );
174
+ /* Unlock the lock so it's safe to free it */
175
+ if (self -> rlock_count > 0 )
176
+ PyThread_release_lock (self -> rlock_lock );
177
+
178
+ PyThread_free_lock (self -> rlock_lock );
179
+ Py_TYPE (self )-> tp_free (self );
180
+ }
181
+
182
+ static PyObject *
183
+ rlock_acquire (rlockobject * self , PyObject * args , PyObject * kwds )
184
+ {
185
+ char * kwlist [] = {"blocking" , NULL };
186
+ int blocking = 1 ;
187
+ long tid ;
188
+ int r = 1 ;
189
+
190
+ if (!PyArg_ParseTupleAndKeywords (args , kwds , "|i:acquire" , kwlist ,
191
+ & blocking ))
192
+ return NULL ;
193
+
194
+ tid = PyThread_get_thread_ident ();
195
+ if (self -> rlock_count > 0 && tid == self -> rlock_owner ) {
196
+ unsigned long count = self -> rlock_count + 1 ;
197
+ if (count <= self -> rlock_count ) {
198
+ PyErr_SetString (PyExc_OverflowError ,
199
+ "Internal lock count overflowed" );
200
+ return NULL ;
201
+ }
202
+ self -> rlock_count = count ;
203
+ Py_RETURN_TRUE ;
204
+ }
205
+
206
+ if (self -> rlock_count > 0 ||
207
+ !PyThread_acquire_lock (self -> rlock_lock , 0 )) {
208
+ if (!blocking ) {
209
+ Py_RETURN_FALSE ;
210
+ }
211
+ Py_BEGIN_ALLOW_THREADS
212
+ r = PyThread_acquire_lock (self -> rlock_lock , blocking );
213
+ Py_END_ALLOW_THREADS
214
+ }
215
+ if (r ) {
216
+ assert (self -> rlock_count == 0 );
217
+ self -> rlock_owner = tid ;
218
+ self -> rlock_count = 1 ;
219
+ }
220
+
221
+ return PyBool_FromLong (r );
222
+ }
223
+
224
+ PyDoc_STRVAR (rlock_acquire_doc ,
225
+ "acquire(blocking=True) -> bool\n\
226
+ \n\
227
+ Lock the lock. `blocking` indicates whether we should wait\n\
228
+ for the lock to be available or not. If `blocking` is False\n\
229
+ and another thread holds the lock, the method will return False\n\
230
+ immediately. If `blocking` is True and another thread holds\n\
231
+ the lock, the method will wait for the lock to be released,\n\
232
+ take it and then return True.\n\
233
+ (note: the blocking operation is not interruptible.)\n\
234
+ \n\
235
+ In all other cases, the method will return True immediately.\n\
236
+ Precisely, if the current thread already holds the lock, its\n\
237
+ internal counter is simply incremented. If nobody holds the lock,\n\
238
+ the lock is taken and its internal counter initialized to 1." );
239
+
240
+ static PyObject *
241
+ rlock_release (rlockobject * self )
242
+ {
243
+ long tid = PyThread_get_thread_ident ();
244
+
245
+ if (self -> rlock_count == 0 || self -> rlock_owner != tid ) {
246
+ PyErr_SetString (PyExc_RuntimeError ,
247
+ "cannot release un-acquired lock" );
248
+ return NULL ;
249
+ }
250
+ if (-- self -> rlock_count == 0 ) {
251
+ self -> rlock_owner = 0 ;
252
+ PyThread_release_lock (self -> rlock_lock );
253
+ }
254
+ Py_RETURN_NONE ;
255
+ }
256
+
257
+ PyDoc_STRVAR (rlock_release_doc ,
258
+ "release()\n\
259
+ \n\
260
+ Release the lock, allowing another thread that is blocked waiting for\n\
261
+ the lock to acquire the lock. The lock must be in the locked state,\n\
262
+ and must be locked by the same thread that unlocks it; otherwise a\n\
263
+ `RuntimeError` is raised.\n\
264
+ \n\
265
+ Do note that if the lock was acquire()d several times in a row by the\n\
266
+ current thread, release() needs to be called as many times for the lock\n\
267
+ to be available for other threads." );
268
+
269
+ static PyObject *
270
+ rlock_acquire_restore (rlockobject * self , PyObject * arg )
271
+ {
272
+ long owner ;
273
+ unsigned long count ;
274
+ int r = 1 ;
275
+
276
+ if (!PyArg_ParseTuple (arg , "kl:_acquire_restore" , & count , & owner ))
277
+ return NULL ;
278
+
279
+ if (!PyThread_acquire_lock (self -> rlock_lock , 0 )) {
280
+ Py_BEGIN_ALLOW_THREADS
281
+ r = PyThread_acquire_lock (self -> rlock_lock , 1 );
282
+ Py_END_ALLOW_THREADS
283
+ }
284
+ if (!r ) {
285
+ PyErr_SetString (ThreadError , "couldn't acquire lock" );
286
+ return NULL ;
287
+ }
288
+ assert (self -> rlock_count == 0 );
289
+ self -> rlock_owner = owner ;
290
+ self -> rlock_count = count ;
291
+ Py_RETURN_NONE ;
292
+ }
293
+
294
+ PyDoc_STRVAR (rlock_acquire_restore_doc ,
295
+ "_acquire_restore(state) -> None\n\
296
+ \n\
297
+ For internal use by `threading.Condition`." );
298
+
299
+ static PyObject *
300
+ rlock_release_save (rlockobject * self )
301
+ {
302
+ long owner ;
303
+ unsigned long count ;
304
+
305
+ owner = self -> rlock_owner ;
306
+ count = self -> rlock_count ;
307
+ self -> rlock_count = 0 ;
308
+ self -> rlock_owner = 0 ;
309
+ PyThread_release_lock (self -> rlock_lock );
310
+ return Py_BuildValue ("kl" , count , owner );
311
+ }
312
+
313
+ PyDoc_STRVAR (rlock_release_save_doc ,
314
+ "_release_save() -> tuple\n\
315
+ \n\
316
+ For internal use by `threading.Condition`." );
317
+
318
+
319
+ static PyObject *
320
+ rlock_is_owned (rlockobject * self )
321
+ {
322
+ long tid = PyThread_get_thread_ident ();
323
+
324
+ if (self -> rlock_count > 0 && self -> rlock_owner == tid ) {
325
+ Py_RETURN_TRUE ;
326
+ }
327
+ Py_RETURN_FALSE ;
328
+ }
329
+
330
+ PyDoc_STRVAR (rlock_is_owned_doc ,
331
+ "_is_owned() -> bool\n\
332
+ \n\
333
+ For internal use by `threading.Condition`." );
334
+
335
+ static PyObject *
336
+ rlock_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
337
+ {
338
+ rlockobject * self ;
339
+
340
+ self = (rlockobject * ) type -> tp_alloc (type , 0 );
341
+ if (self != NULL ) {
342
+ self -> rlock_lock = PyThread_allocate_lock ();
343
+ if (self -> rlock_lock == NULL ) {
344
+ type -> tp_free (self );
345
+ PyErr_SetString (ThreadError , "can't allocate lock" );
346
+ return NULL ;
347
+ }
348
+ self -> in_weakreflist = NULL ;
349
+ self -> rlock_owner = 0 ;
350
+ self -> rlock_count = 0 ;
351
+ }
352
+
353
+ return (PyObject * ) self ;
354
+ }
355
+
356
+ static PyObject *
357
+ rlock_repr (rlockobject * self )
358
+ {
359
+ return PyUnicode_FromFormat ("<%s owner=%ld count=%lu>" ,
360
+ Py_TYPE (self )-> tp_name , self -> rlock_owner , self -> rlock_count );
361
+ }
362
+
363
+
364
+ static PyMethodDef rlock_methods [] = {
365
+ {"acquire" , (PyCFunction )rlock_acquire ,
366
+ METH_VARARGS | METH_KEYWORDS , rlock_acquire_doc },
367
+ {"release" , (PyCFunction )rlock_release ,
368
+ METH_NOARGS , rlock_release_doc },
369
+ {"_is_owned" , (PyCFunction )rlock_is_owned ,
370
+ METH_NOARGS , rlock_is_owned_doc },
371
+ {"_acquire_restore" , (PyCFunction )rlock_acquire_restore ,
372
+ METH_O , rlock_acquire_restore_doc },
373
+ {"_release_save" , (PyCFunction )rlock_release_save ,
374
+ METH_NOARGS , rlock_release_save_doc },
375
+ {"__enter__" , (PyCFunction )rlock_acquire ,
376
+ METH_VARARGS | METH_KEYWORDS , rlock_acquire_doc },
377
+ {"__exit__" , (PyCFunction )rlock_release ,
378
+ METH_VARARGS , rlock_release_doc },
379
+ {NULL , NULL } /* sentinel */
380
+ };
381
+
382
+
383
+ static PyTypeObject RLocktype = {
384
+ PyVarObject_HEAD_INIT (& PyType_Type , 0 )
385
+ "_thread.RLock" , /*tp_name*/
386
+ sizeof (rlockobject ), /*tp_size*/
387
+ 0 , /*tp_itemsize*/
388
+ /* methods */
389
+ (destructor )rlock_dealloc , /*tp_dealloc*/
390
+ 0 , /*tp_print*/
391
+ 0 , /*tp_getattr*/
392
+ 0 , /*tp_setattr*/
393
+ 0 , /*tp_reserved*/
394
+ (reprfunc )rlock_repr , /*tp_repr*/
395
+ 0 , /*tp_as_number*/
396
+ 0 , /*tp_as_sequence*/
397
+ 0 , /*tp_as_mapping*/
398
+ 0 , /*tp_hash*/
399
+ 0 , /*tp_call*/
400
+ 0 , /*tp_str*/
401
+ 0 , /*tp_getattro*/
402
+ 0 , /*tp_setattro*/
403
+ 0 , /*tp_as_buffer*/
404
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
405
+ 0 , /*tp_doc*/
406
+ 0 , /*tp_traverse*/
407
+ 0 , /*tp_clear*/
408
+ 0 , /*tp_richcompare*/
409
+ offsetof(rlockobject , in_weakreflist ), /*tp_weaklistoffset*/
410
+ 0 , /*tp_iter*/
411
+ 0 , /*tp_iternext*/
412
+ rlock_methods , /*tp_methods*/
413
+ 0 , /* tp_members */
414
+ 0 , /* tp_getset */
415
+ 0 , /* tp_base */
416
+ 0 , /* tp_dict */
417
+ 0 , /* tp_descr_get */
418
+ 0 , /* tp_descr_set */
419
+ 0 , /* tp_dictoffset */
420
+ 0 , /* tp_init */
421
+ PyType_GenericAlloc , /* tp_alloc */
422
+ rlock_new /* tp_new */
423
+ };
424
+
158
425
static lockobject *
159
426
newlockobject (void )
160
427
{
@@ -752,6 +1019,8 @@ PyInit__thread(void)
752
1019
return NULL ;
753
1020
if (PyType_Ready (& Locktype ) < 0 )
754
1021
return NULL ;
1022
+ if (PyType_Ready (& RLocktype ) < 0 )
1023
+ return NULL ;
755
1024
756
1025
/* Create the module and add the functions */
757
1026
m = PyModule_Create (& threadmodule );
@@ -766,6 +1035,10 @@ PyInit__thread(void)
766
1035
Py_INCREF (& Locktype );
767
1036
PyDict_SetItemString (d , "LockType" , (PyObject * )& Locktype );
768
1037
1038
+ Py_INCREF (& RLocktype );
1039
+ if (PyModule_AddObject (m , "RLock" , (PyObject * )& RLocktype ) < 0 )
1040
+ return NULL ;
1041
+
769
1042
Py_INCREF (& localtype );
770
1043
if (PyModule_AddObject (m , "_local" , (PyObject * )& localtype ) < 0 )
771
1044
return NULL ;
0 commit comments