7
7
#include < mutex>
8
8
#include < set>
9
9
10
- std::unique_ptr<std:: mutex> _lock_set_mutex = std::make_unique<std::mutex>() ;
10
+ std::mutex _lock_set_mutex;
11
11
12
12
// ----------------------------------------------------------------------------
13
13
// Lock class
@@ -35,14 +35,25 @@ Lock_init(Lock* self, PyObject* args, PyObject* kwargs)
35
35
{
36
36
AllowThreads _;
37
37
38
- std::lock_guard<std::mutex> guard (* _lock_set_mutex);
38
+ std::lock_guard<std::mutex> guard (_lock_set_mutex);
39
39
40
40
lock_set.insert (self);
41
41
}
42
42
43
43
return 0 ;
44
44
}
45
45
46
+ // ----------------------------------------------------------------------------
47
+ static inline void
48
+ _Lock_maybe_leak (Lock* self)
49
+ {
50
+ // This function is used to ensure that the mutex is not leaked if it is
51
+ // still locked when the lock object is deallocated.
52
+ if (self->_locked ) {
53
+ self->_mutex .release (); // DEV: This releases the unique_ptr, not the mutex!
54
+ }
55
+ }
56
+
46
57
// ----------------------------------------------------------------------------
47
58
static void
48
59
Lock_dealloc (Lock* self)
@@ -51,11 +62,13 @@ Lock_dealloc(Lock* self)
51
62
{
52
63
AllowThreads _;
53
64
54
- std::lock_guard<std::mutex> guard (* _lock_set_mutex);
65
+ std::lock_guard<std::mutex> guard (_lock_set_mutex);
55
66
56
67
lock_set.erase (self);
57
68
}
58
69
70
+ _Lock_maybe_leak (self);
71
+
59
72
self->_mutex = nullptr ;
60
73
61
74
Py_TYPE (self)->tp_free ((PyObject*)self);
@@ -153,6 +166,7 @@ Lock_exit(Lock* self, PyObject* args, PyObject* kwargs)
153
166
static inline void
154
167
Lock_reset (Lock* self)
155
168
{
169
+ _Lock_maybe_leak (self);
156
170
self->_mutex = std::make_unique<std::timed_mutex>();
157
171
self->_locked = 0 ;
158
172
}
@@ -212,26 +226,38 @@ RLock_init(RLock* self, PyObject* args, PyObject* kwargs)
212
226
{
213
227
AllowThreads _;
214
228
215
- std::lock_guard<std::mutex> guard (* _lock_set_mutex);
229
+ std::lock_guard<std::mutex> guard (_lock_set_mutex);
216
230
217
231
rlock_set.insert (self);
218
232
}
219
233
220
234
return 0 ;
221
235
}
222
236
237
+ // ----------------------------------------------------------------------------
238
+ static inline void
239
+ _RLock_maybe_leak (RLock* self)
240
+ {
241
+ // This function is used to ensure that the mutex is not leaked if it is
242
+ // still locked when the re-entrant lock object is deallocated.
243
+ if (self->_locked ) {
244
+ self->_mutex .release (); // DEV: This releases the unique_ptr, not the mutex!
245
+ }
246
+ }
247
+
223
248
// ----------------------------------------------------------------------------
224
249
static void
225
250
RLock_dealloc (RLock* self)
226
251
{
227
252
{
228
253
AllowThreads _;
229
254
230
- std::lock_guard<std::mutex> guard (* _lock_set_mutex);
255
+ std::lock_guard<std::mutex> guard (_lock_set_mutex);
231
256
232
257
rlock_set.erase (self);
233
258
}
234
259
260
+ _RLock_maybe_leak (self);
235
261
self->_mutex = nullptr ;
236
262
237
263
Py_TYPE (self)->tp_free ((PyObject*)self);
@@ -329,6 +355,7 @@ RLock_exit(RLock* self, PyObject* args, PyObject* kwargs)
329
355
static inline void
330
356
RLock_reset (RLock* self)
331
357
{
358
+ _RLock_maybe_leak (self);
332
359
self->_mutex = std::make_unique<std::recursive_timed_mutex>();
333
360
self->_locked = 0 ;
334
361
}
@@ -380,8 +407,33 @@ lock_reset_locks(PyObject* Py_UNUSED(self), PyObject* Py_UNUSED(args))
380
407
RLock_reset (rlock);
381
408
}
382
409
383
- // Reset the lock set mutex too!
384
- _lock_set_mutex = std::make_unique<std::mutex>();
410
+ _lock_set_mutex.unlock ();
411
+
412
+ Py_RETURN_NONE;
413
+ }
414
+
415
+ // ----------------------------------------------------------------------------
416
+ static PyObject*
417
+ lock_begin_reset_locks (PyObject* Py_UNUSED (self), PyObject* Py_UNUSED(args))
418
+ {
419
+ // This function is called before a fork to ensure that the lock set mutex
420
+ // is not held by any thread.
421
+ {
422
+ AllowThreads _;
423
+
424
+ _lock_set_mutex.lock ();
425
+ }
426
+
427
+ Py_RETURN_NONE;
428
+ }
429
+
430
+ // ----------------------------------------------------------------------------
431
+ static PyObject*
432
+ lock_end_reset_locks (PyObject* Py_UNUSED (self), PyObject* Py_UNUSED(args))
433
+ {
434
+ // This function is called after a fork to ensure that the lock set mutex
435
+ // is released and can be used by the new process.
436
+ _lock_set_mutex.unlock ();
385
437
386
438
Py_RETURN_NONE;
387
439
}
0 commit comments