@@ -56,39 +56,50 @@ typedef struct {
5656 PyObject * py_backend ;
5757} pgit_odb_backend ;
5858
59+ /*
60+ * The callbacks below may be called by libgit2 without the GIL: cffi releases
61+ * it around every C call, and functions such as git_index_add_bypath end up
62+ * here. So they must acquire it before calling into Python.
63+ */
64+
5965static int
6066pgit_odb_backend_read (void * * ptr , size_t * sz , git_object_t * type ,
6167 git_odb_backend * _be , const git_oid * oid )
6268{
6369 pgit_odb_backend * be = (pgit_odb_backend * )_be ;
70+ PyObject * result = NULL ;
71+ int err = GIT_EUSER ;
72+ PyGILState_STATE gil = PyGILState_Ensure ();
6473
6574 PyObject * py_oid = git_oid_to_python (oid );
6675 if (py_oid == NULL )
67- return GIT_EUSER ;
76+ goto done ;
6877
69- PyObject * result = PyObject_CallMethod (be -> py_backend , "read_cb" , "N" , py_oid );
70- if (result == NULL )
71- return git_error_for_exc ();
78+ result = PyObject_CallMethod (be -> py_backend , "read_cb" , "N" , py_oid );
79+ if (result == NULL ) {
80+ err = git_error_for_exc ();
81+ goto done ;
82+ }
7283
7384 const char * bytes ;
7485 Py_ssize_t type_value ;
7586 Py_ssize_t py_sz ;
76- if (!PyArg_ParseTuple (result , "ny#" , & type_value , & bytes , & py_sz ) || !bytes ) {
77- Py_DECREF (result );
78- return GIT_EUSER ;
79- }
87+ if (!PyArg_ParseTuple (result , "ny#" , & type_value , & bytes , & py_sz ) || !bytes )
88+ goto done ;
8089 * type = (git_object_t )type_value ;
8190 * sz = (size_t )py_sz ;
8291
8392 * ptr = git_odb_backend_data_alloc (_be , * sz );
84- if (!* ptr ) {
85- Py_DECREF (result );
86- return GIT_EUSER ;
87- }
93+ if (!* ptr )
94+ goto done ;
8895
8996 memcpy (* ptr , bytes , * sz );
90- Py_DECREF (result );
91- return 0 ;
97+ err = 0 ;
98+
99+ done :
100+ Py_XDECREF (result );
101+ PyGILState_Release (gil );
102+ return err ;
92103}
93104
94105static int
@@ -101,94 +112,119 @@ pgit_odb_backend_read_prefix(git_oid *oid_out, void **ptr, size_t *sz, git_objec
101112
102113 // Call callback
103114 pgit_odb_backend * be = (pgit_odb_backend * )_be ;
115+ int err = GIT_EUSER ;
116+ PyGILState_STATE gil = PyGILState_Ensure ();
104117 PyObject * result = PyObject_CallMethod (be -> py_backend , "read_prefix_cb" , "s#" , short_id_hex , len );
105- if (result == NULL )
106- return git_error_for_exc ();
118+ if (result == NULL ) {
119+ err = git_error_for_exc ();
120+ goto done ;
121+ }
107122
108123 // Parse output from callback
109124 PyObject * py_oid_out ;
110125 Py_ssize_t type_value ;
111126 Py_ssize_t py_sz ;
112127 const char * bytes ;
113- if (!PyArg_ParseTuple (result , "ny#O" , & type_value , & bytes , & py_sz , & py_oid_out ) || !bytes ) {
114- Py_DECREF (result );
115- return GIT_EUSER ;
116- }
128+ if (!PyArg_ParseTuple (result , "ny#O" , & type_value , & bytes , & py_sz , & py_oid_out ) || !bytes )
129+ goto done ;
117130 * type = (git_object_t )type_value ;
118131 * sz = (size_t )py_sz ;
119132
120133 * ptr = git_odb_backend_data_alloc (_be , * sz );
121- if (!* ptr ) {
122- Py_DECREF (result );
123- return GIT_EUSER ;
124- }
134+ if (!* ptr )
135+ goto done ;
125136
126137 memcpy (* ptr , bytes , * sz );
127- size_t oid_len = py_oid_to_git_oid (py_oid_out , oid_out );
128- Py_DECREF (result );
129- if (oid_len == 0 )
130- return GIT_EUSER ;
131- return 0 ;
138+ if (py_oid_to_git_oid (py_oid_out , oid_out ) == 0 )
139+ goto done ;
140+ err = 0 ;
141+
142+ done :
143+ Py_XDECREF (result );
144+ PyGILState_Release (gil );
145+ return err ;
132146}
133147
134148static int
135149pgit_odb_backend_read_header (size_t * len , git_object_t * type ,
136150 git_odb_backend * _be , const git_oid * oid )
137151{
138152 pgit_odb_backend * be = (pgit_odb_backend * )_be ;
153+ PyObject * result = NULL ;
154+ int err = GIT_EUSER ;
155+ PyGILState_STATE gil = PyGILState_Ensure ();
139156
140157 PyObject * py_oid = git_oid_to_python (oid );
141158 if (py_oid == NULL )
142- return GIT_EUSER ;
159+ goto done ;
143160
144- PyObject * result = PyObject_CallMethod (be -> py_backend , "read_header_cb" , "N" , py_oid );
145- if (result == NULL )
146- return git_error_for_exc ();
161+ result = PyObject_CallMethod (be -> py_backend , "read_header_cb" , "N" , py_oid );
162+ if (result == NULL ) {
163+ err = git_error_for_exc ();
164+ goto done ;
165+ }
147166
148167 Py_ssize_t type_value ;
149- if (!PyArg_ParseTuple (result , "nn" , & type_value , len )) {
150- Py_DECREF (result );
151- return GIT_EUSER ;
152- }
168+ if (!PyArg_ParseTuple (result , "nn" , & type_value , len ))
169+ goto done ;
153170 * type = (git_object_t )type_value ;
171+ err = 0 ;
154172
155- Py_DECREF (result );
156- return 0 ;
173+ done :
174+ Py_XDECREF (result );
175+ PyGILState_Release (gil );
176+ return err ;
157177}
158178
159179static int
160180pgit_odb_backend_write (git_odb_backend * _be , const git_oid * oid ,
161181 const void * data , size_t sz , git_object_t typ )
162182{
163183 pgit_odb_backend * be = (pgit_odb_backend * )_be ;
184+ PyObject * result = NULL ;
185+ int err = GIT_EUSER ;
186+ PyGILState_STATE gil = PyGILState_Ensure ();
164187
165188 PyObject * py_oid = git_oid_to_python (oid );
166189 if (py_oid == NULL )
167- return GIT_EUSER ;
190+ goto done ;
168191
169- PyObject * result = PyObject_CallMethod (be -> py_backend , "write_cb" , "Ny#n" , py_oid , data , sz , typ );
170- if (result == NULL )
171- return git_error_for_exc ();
192+ result = PyObject_CallMethod (be -> py_backend , "write_cb" , "Ny#n" , py_oid , data , sz , typ );
193+ if (result == NULL ) {
194+ err = git_error_for_exc ();
195+ goto done ;
196+ }
197+ err = 0 ;
172198
173- Py_DECREF (result );
174- return 0 ;
199+ done :
200+ Py_XDECREF (result );
201+ PyGILState_Release (gil );
202+ return err ;
175203}
176204
177205static int
178206pgit_odb_backend_exists (git_odb_backend * _be , const git_oid * oid )
179207{
180208 pgit_odb_backend * be = (pgit_odb_backend * )_be ;
209+ PyObject * result = NULL ;
210+ int r = GIT_EUSER ;
211+ PyGILState_STATE gil = PyGILState_Ensure ();
181212
182213 PyObject * py_oid = git_oid_to_python (oid );
183214 if (py_oid == NULL )
184- return GIT_EUSER ;
215+ goto done ;
216+
217+ result = PyObject_CallMethod (be -> py_backend , "exists_cb" , "N" , py_oid );
218+ if (result == NULL ) {
219+ r = git_error_for_exc ();
220+ goto done ;
221+ }
185222
186- PyObject * result = PyObject_CallMethod (be -> py_backend , "exists_cb" , "N" , py_oid );
187- if (result == NULL )
188- return git_error_for_exc ();
223+ r = PyObject_IsTrue (result );
189224
190- int r = PyObject_IsTrue (result );
191- Py_DECREF (result );
225+ done :
226+ Py_XDECREF (result );
227+ PyGILState_Release (gil );
192228 return r ;
193229}
194230
@@ -202,67 +238,86 @@ pgit_odb_backend_exists_prefix(git_oid *out, git_odb_backend *_be,
202238
203239 // Call callback
204240 pgit_odb_backend * be = (pgit_odb_backend * )_be ;
241+ int err = GIT_EUSER ;
242+ PyGILState_STATE gil = PyGILState_Ensure ();
205243 PyObject * py_oid = PyObject_CallMethod (be -> py_backend , "exists_prefix_cb" , "s#" , short_id_hex , len );
206- if (py_oid == NULL )
207- return git_error_for_exc ();
244+ if (py_oid == NULL ) {
245+ err = git_error_for_exc ();
246+ goto done ;
247+ }
208248
209- size_t oid_len = py_oid_to_git_oid (py_oid , out );
210- Py_DECREF (py_oid );
211- if (oid_len == 0 )
212- return GIT_EUSER ;
213- return 0 ;
249+ if (py_oid_to_git_oid (py_oid , out ) == 0 )
250+ goto done ;
251+ err = 0 ;
252+
253+ done :
254+ Py_XDECREF (py_oid );
255+ PyGILState_Release (gil );
256+ return err ;
214257}
215258
216259static int
217260pgit_odb_backend_refresh (git_odb_backend * _be )
218261{
219262 pgit_odb_backend * be = (pgit_odb_backend * )_be ;
263+ PyGILState_STATE gil = PyGILState_Ensure ();
220264 PyObject_CallMethod (be -> py_backend , "refresh_cb" , NULL );
221- return git_error_for_exc ();
265+ int err = git_error_for_exc ();
266+ PyGILState_Release (gil );
267+ return err ;
222268}
223269
224270static int
225271pgit_odb_backend_foreach (git_odb_backend * _be ,
226272 git_odb_foreach_cb cb , void * payload )
227273{
228274 PyObject * item ;
275+ PyObject * iterator = NULL ;
229276 git_oid oid ;
230277 pgit_odb_backend * be = (pgit_odb_backend * )_be ;
278+ int err = GIT_EUSER ;
279+ PyGILState_STATE gil = PyGILState_Ensure ();
231280
232281 /* Call the Python __iter__ method directly. PyObject_GetIter would invoke
233282 * the C tp_iter slot (OdbBackend_as_iter), which calls this function back
234283 * and causes infinite recursion for Python backends. */
235284 PyObject * iter_method = PyObject_GetAttrString ((PyObject * )be -> py_backend , "__iter__" );
236- if (iter_method == NULL )
237- return git_error_for_exc ();
285+ if (iter_method == NULL ) {
286+ err = git_error_for_exc ();
287+ goto done ;
288+ }
238289
239- PyObject * iterator = PyObject_CallObject (iter_method , NULL );
290+ iterator = PyObject_CallObject (iter_method , NULL );
240291 Py_DECREF (iter_method );
241- if (iterator == NULL )
242- return git_error_for_exc ();
292+ if (iterator == NULL ) {
293+ err = git_error_for_exc ();
294+ goto done ;
295+ }
243296
244297 while ((item = PyIter_Next (iterator ))) {
245298 size_t len = py_oid_to_git_oid (item , & oid );
246299 Py_DECREF (item );
247- if (len == 0 ) {
248- Py_DECREF (iterator );
249- return GIT_EUSER ;
250- }
251- if (cb (& oid , payload ) != 0 ) {
252- Py_DECREF (iterator );
253- return GIT_EUSER ;
254- }
300+ if (len == 0 )
301+ goto done ;
302+ if (cb (& oid , payload ) != 0 )
303+ goto done ;
255304 }
256305
257- Py_DECREF (iterator );
258- return git_error_for_exc ();
306+ err = git_error_for_exc ();
307+
308+ done :
309+ Py_XDECREF (iterator );
310+ PyGILState_Release (gil );
311+ return err ;
259312}
260313
261314static void
262315pgit_odb_backend_free (git_odb_backend * backend )
263316{
264317 pgit_odb_backend * custom_backend = (pgit_odb_backend * )backend ;
318+ PyGILState_STATE gil = PyGILState_Ensure ();
265319 Py_DECREF (custom_backend -> py_backend );
320+ PyGILState_Release (gil );
266321}
267322
268323int
0 commit comments