All pastes #717800 Raw Edit

Untitled

public text v1 · immutable
#717800 ·published 2007-09-27 21:37 UTC
rendered paste body
Index: libtransmission/peer-mgr.c
===================================================================
--- libtransmission/peer-mgr.c  (revision 3208)
+++ libtransmission/peer-mgr.c  (working copy)
@@ -28,6 +28,7 @@
 #include "ptrarray.h"
 #include "trevent.h"
 #include "utils.h"
+#include "platform.h"
 
 enum
 {
@@ -83,6 +84,7 @@
 {
     uint8_t hash[SHA_DIGEST_LENGTH];
     tr_ptrArray * peers; /* tr_peer */
+    tr_lock * peerLock;
     tr_timer * reconnectTimer;
     tr_timer * reconnectSoonTimer;
     tr_timer * rechokeTimer;
@@ -199,7 +201,11 @@
     {
         peer = tr_new0( tr_peer, 1 );
         memcpy( &peer->in_addr, in_addr, sizeof(struct in_addr) );
-        tr_ptrArrayInsertSorted( torrent->peers, peer, peerCompare );
+        tr_lockLock(torrent->peerLock);
+        {
+            tr_ptrArrayInsertSorted( torrent->peers, peer, peerCompare );
+        }
+        tr_lockUnlock(torrent->peerLock);
     }
 
     return peer;
@@ -247,6 +253,7 @@
 
     assert( manager != NULL );
     assert( t != NULL );
+    assert( t->peerLock != NULL );
     assert( t->peers != NULL );
     assert( getExistingTorrent( manager, t->hash ) != NULL );
 
@@ -257,14 +264,19 @@
     tr_timerFree( &t->rechokeTimer );
     tr_timerFree( &t->rechokeSoonTimer );
     tr_timerFree( &t->refillTimer );
-
-    peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &size );
-    for( i=0; i<size; ++i )
-        freePeer( peers[i] );
-
-    tr_bitfieldFree( t->requested );
-    tr_ptrArrayFree( t->peers );
-    tr_ptrArrayRemoveSorted( manager->torrents, t, torrentCompare );
+    
+    tr_lockLock(t->peerLock);
+    {
+        peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+        for( i=0; i<size; ++i )
+            freePeer( peers[i] );
+        
+        tr_bitfieldFree( t->requested );
+        tr_ptrArrayFree( t->peers );
+        tr_ptrArrayRemoveSorted( manager->torrents, t, torrentCompare );
+    }
+    tr_lockUnlock(t->peerLock);
+    tr_lockFree(t->peerLock);
     tr_free( t );
 
     assert( getExistingTorrent( manager, hash ) == NULL );
@@ -302,13 +314,20 @@
 getConnectedPeers( Torrent * t, int * setmeCount )
 {
     int i, peerCount, connectionCount;
-    tr_peer **peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
-    tr_peer **ret = tr_new( tr_peer*, peerCount );
+    tr_peer **peers;
+    tr_peer **ret;
+    
+    tr_lockLock(t->peerLock);
+    {
+        peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
+        ret = tr_new( tr_peer*, peerCount );
+        
+        for( i=connectionCount=0; i<peerCount; ++i )
+            if( peers[i]->msgs != NULL )
+                ret[connectionCount++] = peers[i];
+    }
+    tr_lockUnlock(t->peerLock);
 
-    for( i=connectionCount=0; i<peerCount; ++i )
-        if( peers[i]->msgs != NULL )
-            ret[connectionCount++] = peers[i];
-
     *setmeCount = connectionCount;
     return ret;
 }
@@ -862,22 +881,30 @@
 {
     const Torrent * t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
     int i, peerCount;
-    const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
-    tr_pex * pex = tr_new( tr_pex, peerCount );
-    tr_pex * walk = pex;
+    const tr_peer ** peers;
+    tr_pex * pex;
+    tr_pex * walk;
 
-    for( i=0; i<peerCount; ++i, ++walk )
+    tr_lockLock(t->peerLock);
     {
-        const tr_peer * peer = peers[i];
-
-        walk->in_addr = peer->in_addr;
-
-        walk->port = peer->port;
-
-        walk->flags = 0;
-        if( peer->peerSupportsEncryption ) walk->flags |= 1;
-        if( peer->progress >= 1.0 )        walk->flags |= 2;
+        peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
+        pex = tr_new( tr_pex, peerCount );
+        walk = pex;
+        
+        for( i=0; i<peerCount; ++i, ++walk )
+        {
+            const tr_peer * peer = peers[i];
+            
+            walk->in_addr = peer->in_addr;
+            
+            walk->port = peer->port;
+            
+            walk->flags = 0;
+            if( peer->peerSupportsEncryption ) walk->flags |= 1;
+            if( peer->progress >= 1.0 )        walk->flags |= 2;
+        }
     }
+    tr_lockUnlock(t->peerLock);
 
     assert( ( walk - pex ) == peerCount );
     qsort( pex, peerCount, sizeof(tr_pex), tr_pexCompare );
@@ -918,7 +945,12 @@
     t = tr_new0( Torrent, 1 );
     t->manager = manager;
     t->tor = tor;
-    t->peers = tr_ptrArrayNew( );
+    t->peerLock = tr_lockNew();
+    tr_lockLock(t->peerLock);
+    {
+        t->peers = tr_ptrArrayNew( );
+    }
+    tr_lockUnlock(t->peerLock);
     t->requested = tr_bitfieldNew( tor->blockCount );
     restartChokeTimer( t );
     restartReconnectTimer( t );
@@ -960,10 +992,16 @@
             tab[i] = -1;
         else {
             int j, peerCount;
-            const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
-            for( j=0; j<peerCount; ++j )
-                if( tr_bitfieldHas( peers[j]->have, i ) )
-                    ++tab[i];
+            const tr_peer ** peers;
+            
+            tr_lockLock(t->peerLock);
+            {
+                peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
+                for( j=0; j<peerCount; ++j )
+                    if( tr_bitfieldHas( peers[j]->have, i ) )
+                        ++tab[i];
+            }
+            tr_lockUnlock(t->peerLock);
         }
     }
 }
@@ -979,11 +1017,15 @@
     tr_bitfield * pieces;
 
     t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
-    peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
     pieces = tr_bitfieldDup( tr_cpPieceBitfield( t->tor->completion ) );
-    for( i=0; i<size; ++i )
-        if( peers[i]->io != NULL )
-            tr_bitfieldAnd( pieces, peers[i]->have );
+    tr_lockLock(t->peerLock);
+    {
+        peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+        for( i=0; i<size; ++i )
+            if( peers[i]->io != NULL )
+                tr_bitfieldAnd( pieces, peers[i]->have );
+    }
+    tr_lockUnlock(t->peerLock);
 
     return pieces;
 }
@@ -999,33 +1041,39 @@
 {
     int i, size;
     const Torrent * t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
-    const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+    const tr_peer ** peers;
 
-    *setmePeersTotal          = size;
-    *setmePeersConnected      = 0;
-    *setmePeersSendingToUs    = 0;
-    *setmePeersGettingFromUs  = 0;
-
-    for( i=0; i<TR_PEER_FROM__MAX; ++i )
-        setmePeersFrom[i] = 0;
-
-    for( i=0; i<size; ++i )
+    tr_lockLock(t->peerLock);
     {
-        const tr_peer * peer = peers[i];
-
-        if( peer->io == NULL ) /* not connected */
-            continue;
-
-        ++*setmePeersConnected;
-
-        ++setmePeersFrom[peer->from];
-
-        if( tr_peerIoGetRateToPeer( peer->io ) > 0.01 )
-            ++*setmePeersGettingFromUs;
-
-        if( tr_peerIoGetRateToClient( peer->io ) > 0.01 )
-            ++*setmePeersSendingToUs;
+        peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+        
+        *setmePeersTotal          = size;
+        *setmePeersConnected      = 0;
+        *setmePeersSendingToUs    = 0;
+        *setmePeersGettingFromUs  = 0;
+        
+        for( i=0; i<TR_PEER_FROM__MAX; ++i )
+            setmePeersFrom[i] = 0;
+        
+        for( i=0; i<size; ++i )
+        {
+            const tr_peer * peer = peers[i];
+            
+            if( peer->io == NULL ) /* not connected */
+                continue;
+            
+            ++*setmePeersConnected;
+            
+            ++setmePeersFrom[peer->from];
+            
+            if( tr_peerIoGetRateToPeer( peer->io ) > 0.01 )
+                ++*setmePeersGettingFromUs;
+            
+            if( tr_peerIoGetRateToClient( peer->io ) > 0.01 )
+                ++*setmePeersSendingToUs;
+        }
     }
+    tr_lockUnlock(t->peerLock);
 }
 
 struct tr_peer_stat *
@@ -1035,29 +1083,33 @@
 {
     int i, size;
     const Torrent * t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
-    const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+    const tr_peer ** peers;
     tr_peer_stat * ret;
 
-    ret = tr_new0( tr_peer_stat, size );
-
-    for( i=0; i<size; ++i )
+    tr_lockLock(t->peerLock);
     {
-        const tr_peer * peer = peers[i];
-        const int live = peer->io != NULL;
-        tr_peer_stat * stat = ret + i;
-
-        tr_netNtop( &peer->in_addr, stat->addr, sizeof(stat->addr) );
-        stat->port             = peer->port;
-        stat->from             = peer->from;
-        stat->client           = peer->client;
-        stat->progress         = peer->progress;
-        stat->isConnected      = live ? 1 : 0;
-        stat->isEncrypted      = tr_peerIoIsEncrypted( peer->io ) ? 1 : 0;
-        stat->uploadToRate     = tr_peerIoGetRateToPeer( peer->io );
-        stat->downloadFromRate = tr_peerIoGetRateToClient( peer->io );
-        stat->isDownloading    = stat->uploadToRate > 0.01;
-        stat->isUploading      = stat->downloadFromRate > 0.01;
+        peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+        ret = tr_new0( tr_peer_stat, size );
+        for( i=0; i<size; ++i )
+        {
+            const tr_peer * peer = peers[i];
+            const int live = peer->io != NULL;
+            tr_peer_stat * stat = ret + i;
+            
+            tr_netNtop( &peer->in_addr, stat->addr, sizeof(stat->addr) );
+            stat->port             = peer->port;
+            stat->from             = peer->from;
+            stat->client           = peer->client;
+            stat->progress         = peer->progress;
+            stat->isConnected      = live ? 1 : 0;
+            stat->isEncrypted      = tr_peerIoIsEncrypted( peer->io ) ? 1 : 0;
+            stat->uploadToRate     = tr_peerIoGetRateToPeer( peer->io );
+            stat->downloadFromRate = tr_peerIoGetRateToClient( peer->io );
+            stat->isDownloading    = stat->uploadToRate > 0.01;
+            stat->isUploading      = stat->downloadFromRate > 0.01;
+        }
     }
+    tr_lockUnlock(t->peerLock);
 
     *setmeCount = size;
     return ret;
@@ -1242,79 +1294,84 @@
 {
     int i, size, liveCount;
     Torrent * t = vt;
-    tr_peer ** peers = (tr_peer**) tr_ptrArrayPeek( t->peers, &size );
+    tr_peer ** peers;
     const int isSeeding = tr_cpGetStatus( t->tor->completion ) != TR_CP_INCOMPLETE;
 
-    /* how many connections do we have? */
-    for( i=liveCount=0; i<size; ++i )
-        if( peers[i]->msgs != NULL )
-            ++liveCount;
-
-    /* destroy and/or disconnect from some peers */
-    for( i=0; i<size; )
+    tr_lockLock(t->peerLock);
     {
-        tr_peer * peer = peers[i];
-
-        if( peer->doPurge ) {
-            tr_ptrArrayErase( t->peers, i, i+1 );
-            freePeer( peer );
-            --size;
-            --liveCount;
-            continue;
-        }
-
-        if( shouldPeerBeDisconnected( t, peer, liveCount, isSeeding ) ) {
-            disconnectPeer( peer );
-            --liveCount;
-        }
-
-        ++i;
-    }
-
-    /* maybe connect to some new peers */ 
-    if( t->isRunning && (liveCount<MAX_CONNECTED_PEERS_PER_TORRENT) )
-    {
-        int poolSize;
-        int left = MAX_CONNECTED_PEERS_PER_TORRENT - liveCount;
-        tr_peer ** pool;
-        tr_peerMgr * manager = t->manager;
-        const time_t now = time( NULL );
-
-        /* make a list of peers we know about but aren't connected to */
-        poolSize = 0;
-        pool = tr_new0( tr_peer*, size );
-        for( i=0; i<size; ++i ) {
+        peers = (tr_peer**) tr_ptrArrayPeek( t->peers, &size );
+        /* how many connections do we have? */
+        for( i=liveCount=0; i<size; ++i )
+            if( peers[i]->msgs != NULL )
+                ++liveCount;
+        
+        /* destroy and/or disconnect from some peers */
+        for( i=0; i<size; )
+        {
             tr_peer * peer = peers[i];
-            if( peer->msgs == NULL )
-                pool[poolSize++] = peer;
+            
+            if( peer->doPurge ) {
+                tr_ptrArrayErase( t->peers, i, i+1 );
+                freePeer( peer );
+                --size;
+                --liveCount;
+                continue;
+            }
+            
+            if( shouldPeerBeDisconnected( t, peer, liveCount, isSeeding ) ) {
+                disconnectPeer( peer );
+                --liveCount;
+            }
+            
+            ++i;
         }
-
-        /* sort them s.t. the ones we've already tried are at the last of the list */
-        qsort( pool, poolSize, sizeof(tr_peer*), comparePeerByConnectionDate );
-
-        /* make some connections */
-        for( i=0; i<poolSize && left>0; ++i )
+        
+        /* maybe connect to some new peers */ 
+        if( t->isRunning && (liveCount<MAX_CONNECTED_PEERS_PER_TORRENT) )
         {
-            tr_peer * peer = pool[i];
-            tr_peerIo * io;
-
-            if( ( now - peer->connectionChangedAt ) < MIN_HANGUP_PERIOD_SEC )
-                break;
-
-            /* already have a handshake pending */
-            if( getExistingHandshake( manager, &peer->in_addr ) != NULL )
-                continue;
-
-            /* initiate a connection to the peer */
-            io = tr_peerIoNewOutgoing( manager->handle, &peer->in_addr, peer->port, t->hash );
-            /*fprintf( stderr, "[%s] connecting to potential peer %s\n", t->tor->info.name, tr_peerIoGetAddrStr(io) );*/
-            peer->connectionChangedAt = time( NULL );
-            initiateHandshake( manager, io );
-            --left;
+            int poolSize;
+            int left = MAX_CONNECTED_PEERS_PER_TORRENT - liveCount;
+            tr_peer ** pool;
+            tr_peerMgr * manager = t->manager;
+            const time_t now = time( NULL );
+            
+            /* make a list of peers we know about but aren't connected to */
+            poolSize = 0;
+            pool = tr_new0( tr_peer*, size );
+            for( i=0; i<size; ++i ) {
+                tr_peer * peer = peers[i];
+                if( peer->msgs == NULL )
+                    pool[poolSize++] = peer;
+            }
+            
+            /* sort them s.t. the ones we've already tried are at the last of the list */
+            qsort( pool, poolSize, sizeof(tr_peer*), comparePeerByConnectionDate );
+            
+            /* make some connections */
+            for( i=0; i<poolSize && left>0; ++i )
+            {
+                tr_peer * peer = pool[i];
+                tr_peerIo * io;
+                
+                if( ( now - peer->connectionChangedAt ) < MIN_HANGUP_PERIOD_SEC )
+                    break;
+                
+                /* already have a handshake pending */
+                if( getExistingHandshake( manager, &peer->in_addr ) != NULL )
+                    continue;
+                
+                /* initiate a connection to the peer */
+                io = tr_peerIoNewOutgoing( manager->handle, &peer->in_addr, peer->port, t->hash );
+                /*fprintf( stderr, "[%s] connecting to potential peer %s\n", t->tor->info.name, tr_peerIoGetAddrStr(io) );*/
+                peer->connectionChangedAt = time( NULL );
+                initiateHandshake( manager, io );
+                --left;
+            }
+            
+            tr_free( pool );
         }
-
-        tr_free( pool );
     }
+    tr_lockUnlock(t->peerLock);
 
     return TRUE;
 }