[pygobject] Do not do any python calls when GObjects are destroyed after the python interpreter has been finaliz



commit e92278692bb51679d6e957c2ac36db64498a7c73
Author: Simon Schampijer <simon schampijer de>
Date:   Fri Jun 15 16:11:21 2012 +0200

    Do not do any python calls when GObjects are destroyed after the python interpreter has been finalized
    
    This happens when pygobject_data_free () function is called after the python
    interpreter shuts down, we can't do python calls after that.
    
    Benzea did the findings because of a bug in Sugar, and commented in this
    SugarLabs ticket: http://bugs.sugarlabs.org/ticket/3670
    
    https://bugzilla.gnome.org/show_bug.cgi?id=678046
    
    Signed-off-by: Benjamin Berg <benzea sugarlabs org>
    Signed-off-by: Martin Pitt <martinpitt gnome org>

 gi/_gobject/pygobject.c |   27 ++++++++++++++++++++++-----
 1 files changed, 22 insertions(+), 5 deletions(-)
---
diff --git a/gi/_gobject/pygobject.c b/gi/_gobject/pygobject.c
index d9d2969..355c6d0 100644
--- a/gi/_gobject/pygobject.c
+++ b/gi/_gobject/pygobject.c
@@ -57,15 +57,28 @@ GQuark pygobject_instance_data_key;
 void
 pygobject_data_free(PyGObjectData *data)
 {
-    PyGILState_STATE state = pyglib_gil_state_ensure();
+    /* This function may be called after the python interpreter has already
+     * been shut down. If this happens, we cannot do any python calls, so just
+     * free the memory. */
+    PyGILState_STATE state;
+    PyThreadState *_save = NULL;
+
     GSList *closures, *tmp;
-    Py_DECREF(data->type);
+
+    if (Py_IsInitialized()) {
+	state = pyglib_gil_state_ensure();
+	Py_DECREF(data->type);
+	/* We cannot use pyg_begin_allow_threads here because this is inside
+	 * a branch. */
+	if (pyg_threads_enabled)
+	    _save = PyEval_SaveThread();
+    }
+
     tmp = closures = data->closures;
 #ifndef NDEBUG
     data->closures = NULL;
     data->type = NULL;
 #endif
-    pyg_begin_allow_threads;
     while (tmp) {
  	GClosure *closure = tmp->data;
  
@@ -74,13 +87,17 @@ pygobject_data_free(PyGObjectData *data)
  	tmp = tmp->next;
  	g_closure_invalidate(closure);
     }
-    pyg_end_allow_threads;
  
     if (data->closures != NULL)
  	g_warning("invalidated all closures, but data->closures != NULL !");
 
     g_free(data);
-    pyglib_gil_state_release(state);
+
+    if (Py_IsInitialized()) {
+	if (pyg_threads_enabled)
+	    PyEval_RestoreThread(_save);
+	pyglib_gil_state_release(state);
+    }
 }
 
 static inline PyGObjectData *



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]