]> granicus.if.org Git - transmission/commitdiff
(trunk libT) #3980 "segfault when adding many torrents remotely" -- possible fix.
authorJordan Lee <jordan@transmissionbt.com>
Sat, 5 Feb 2011 05:03:00 +0000 (05:03 +0000)
committerJordan Lee <jordan@transmissionbt.com>
Sat, 5 Feb 2011 05:03:00 +0000 (05:03 +0000)
gtk/main.c's onRPCChanged() is called from inside the libtransmission thread, yet it still made GTK+ calls to modify the GTK+ client's tr-core object when a torrent was added. This caused a race condition inside of the GTK+ internals. onRPCChanged() already knows to delegate work back to the GTK+ thread when a torrent is removed via RPC. This commit uses the same kind of mechanism to delegate work back to the GTK+ thread when a torrent is added via RPC.

gtk/main.c

index 917204f57c39cd5db422756d8719f555cc51be67..aeeb4a01fcbc2456d0fc2edbbaeed383f2ce6fac 100644 (file)
@@ -449,21 +449,37 @@ signal_handler( int sig )
     }
 }
 
-struct remove_torrent_idle_data
+struct torrent_idle_data
 {
     TrCore * core;
     int id;
 };
 
 static gboolean
-remove_torrent_idle( gpointer gdata )
+rpc_torrent_remove_idle( gpointer gdata )
 {
-    struct remove_torrent_idle_data * data = gdata;
+    struct torrent_idle_data * data = gdata;
+
     tr_core_remove_torrent_from_id( data->core, data->id, FALSE );
+
     g_free( data );
     return FALSE; /* tell g_idle not to call this func twice */
 }
 
+static gboolean
+rpc_torrent_add_idle( gpointer gdata )
+{
+    tr_torrent * tor;
+    struct torrent_idle_data * data = gdata;
+
+    if(( tor = tr_torrentFindFromId( tr_core_session( data->core ), data->id )))
+        tr_core_add_torrent( data->core, tr_torrent_new_preexisting( tor ), TRUE );
+
+    g_free( data );
+    return FALSE; /* tell g_idle not to call this func twice */
+}
+
+
 static void
 setupsighandlers( void )
 {
@@ -487,15 +503,19 @@ onRPCChanged( tr_session            * session,
             gtr_action_activate( "quit" );
             break;
 
-        case TR_RPC_TORRENT_ADDED:
-            tr_core_add_torrent( cbdata->core, tr_torrent_new_preexisting( tor ), TRUE );
+        case TR_RPC_TORRENT_ADDED: {
+            struct torrent_idle_data * data = g_new0( struct torrent_idle_data, 1 );
+            data->id = tr_torrentId( tor );
+            data->core = cbdata->core;
+            gtr_idle_add( rpc_torrent_add_idle, data );
             break;
+        }
 
         case TR_RPC_TORRENT_REMOVING: {
-            struct remove_torrent_idle_data * data = g_new0( struct remove_torrent_idle_data, 1 );
+            struct torrent_idle_data * data = g_new0( struct torrent_idle_data, 1 );
             data->id = tr_torrentId( tor );
             data->core = cbdata->core;
-            gtr_idle_add( remove_torrent_idle, data );
+            gtr_idle_add( rpc_torrent_remove_idle, data );
             status = TR_RPC_NOREMOVE;
             break;
         }