1 |
From 3e3893b0ee381098418d7b28997f6b861c53eff1 Mon Sep 17 00:00:00 2001 |
2 |
From: Alberto Gonzalez <mindhells@gmail.com> |
3 |
Date: Wed, 28 Oct 2020 09:44:09 +0000 |
4 |
Subject: [PATCH] fix #177: avoid GIL deadlock |
5 |
|
6 |
--- |
7 |
fract4d/c/fract4dc/calcargs.cpp | 8 -------- |
8 |
fract4d/c/fract4dc/calcs.cpp | 31 ++++++++++++++++++++++++------- |
9 |
fract4d/c/fract4dmodule.cpp | 1 + |
10 |
3 files changed, 25 insertions(+), 15 deletions(-) |
11 |
|
12 |
diff --git a/fract4d/c/fract4dc/calcargs.cpp b/fract4d/c/fract4dc/calcargs.cpp |
13 |
index 18eb83470..4296427da 100644 |
14 |
--- a/fract4d/c/fract4dc/calcargs.cpp |
15 |
+++ b/fract4d/c/fract4dc/calcargs.cpp |
16 |
@@ -1,5 +1,4 @@ |
17 |
#include "Python.h" |
18 |
-#include <mutex> |
19 |
|
20 |
#include "calcargs.h" |
21 |
|
22 |
@@ -18,13 +17,10 @@ calc_args::calc_args() |
23 |
params = new double[N_PARAMS]; |
24 |
} |
25 |
|
26 |
-static std::mutex ref_count_mutex; |
27 |
- |
28 |
void calc_args::set_cmap(PyObject *pycmap_) |
29 |
{ |
30 |
pycmap = pycmap_; |
31 |
cmap = colormaps::cmap_fromcapsule(pycmap); |
32 |
- const std::lock_guard<std::mutex> lock(ref_count_mutex); |
33 |
Py_XINCREF(pycmap); |
34 |
} |
35 |
|
36 |
@@ -32,7 +28,6 @@ void calc_args::set_pfo(PyObject *pypfo_) |
37 |
{ |
38 |
pypfo = pypfo_; |
39 |
pfo = (loaders::pf_fromcapsule(pypfo))->pfo; |
40 |
- const std::lock_guard<std::mutex> lock(ref_count_mutex); |
41 |
Py_XINCREF(pypfo); |
42 |
} |
43 |
|
44 |
@@ -40,14 +35,12 @@ void calc_args::set_im(PyObject *pyim_) |
45 |
{ |
46 |
pyim = pyim_; |
47 |
im = images::image_fromcapsule(pyim); |
48 |
- const std::lock_guard<std::mutex> lock(ref_count_mutex); |
49 |
Py_XINCREF(pyim); |
50 |
} |
51 |
void calc_args::set_site(PyObject *pysite_) |
52 |
{ |
53 |
pysite = pysite_; |
54 |
site = sites::site_fromcapsule(pysite); |
55 |
- const std::lock_guard<std::mutex> lock(ref_count_mutex); |
56 |
Py_XINCREF(pysite); |
57 |
} |
58 |
|
59 |
@@ -57,7 +50,6 @@ calc_args::~calc_args() |
60 |
#ifdef DEBUG_CREATION |
61 |
fprintf(stderr, "%p : CA : DTOR\n", this); |
62 |
#endif |
63 |
- const std::lock_guard<std::mutex> lock(ref_count_mutex); |
64 |
Py_XDECREF(pycmap); |
65 |
Py_XDECREF(pypfo); |
66 |
Py_XDECREF(pyim); |
67 |
diff --git a/fract4d/c/fract4dc/calcs.cpp b/fract4d/c/fract4dc/calcs.cpp |
68 |
index 1509e8d99..4b9c9b0d3 100644 |
69 |
--- a/fract4d/c/fract4dc/calcs.cpp |
70 |
+++ b/fract4d/c/fract4dc/calcs.cpp |
71 |
@@ -46,11 +46,14 @@ namespace calcs { |
72 |
|
73 |
if (cargs->asynchronous) |
74 |
{ |
75 |
- auto &site = *cargs->site; |
76 |
- site.interrupt(); |
77 |
- site.wait(); |
78 |
- site.start(); |
79 |
- site.set_thread(std::thread(calculation_thread, cargs)); |
80 |
+ std::thread t([cargs](){ |
81 |
+ auto &site = *cargs->site; |
82 |
+ site.interrupt(); |
83 |
+ site.wait(); |
84 |
+ site.start(); |
85 |
+ site.set_thread(std::thread(calculation_thread, cargs)); |
86 |
+ }); |
87 |
+ t.detach(); |
88 |
} |
89 |
else |
90 |
{ |
91 |
@@ -76,6 +79,21 @@ namespace calcs { |
92 |
} |
93 |
} |
94 |
|
95 |
+struct GIL_guard { |
96 |
+ PyGILState_STATE state; |
97 |
+ bool active; |
98 |
+ GIL_guard(): |
99 |
+ state(PyGILState_Ensure()), active(true) {} |
100 |
+ void restore() |
101 |
+ { |
102 |
+ PyGILState_Release(state); |
103 |
+ active = false; |
104 |
+ } |
105 |
+ ~GIL_guard() |
106 |
+ { |
107 |
+ if (active) restore(); |
108 |
+ } |
109 |
+}; |
110 |
|
111 |
void * calculation_thread(calc_args *args) |
112 |
{ |
113 |
@@ -94,9 +112,8 @@ void * calculation_thread(calc_args *args) |
114 |
#ifdef DEBUG_THREADS |
115 |
std::cerr << args << " : CA : ENDCALC(" << std::this_thread::get_id() << ")\n"; |
116 |
#endif |
117 |
- PyGILState_STATE gstate = PyGILState_Ensure(); |
118 |
+ GIL_guard e; |
119 |
delete args; |
120 |
- PyGILState_Release(gstate); |
121 |
return NULL; |
122 |
} |
123 |
|
124 |
diff --git a/fract4d/c/fract4dmodule.cpp b/fract4d/c/fract4dmodule.cpp |
125 |
index 2da6ba72c..5b1ca3f82 100644 |
126 |
--- a/fract4d/c/fract4dmodule.cpp |
127 |
+++ b/fract4d/c/fract4dmodule.cpp |
128 |
@@ -651,6 +651,7 @@ PyInit_fract4dc(void) |
129 |
return NULL; |
130 |
} |
131 |
|
132 |
+ // todo: check this https://docs.python.org/3/c-api/init.html#c.PyEval_InitThreads |
133 |
PyEval_InitThreads(); |
134 |
|
135 |
/* expose some constants */ |