Changeset 2202


Ignore:
Timestamp:
Jun 26, 2007, 6:45:03 PM (14 years ago)
Author:
charles
Message:

Thread safety improvements. Also, stopping/starting/rechecking/etc. torrents no longer blocks the calling thread. Since this a big commit, it will probably create some short-term pain via new bugs.

Location:
trunk
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/cli/transmissioncli.c

    r2149 r2202  
    155155
    156156    /* Open and parse torrent file */
    157     if( !( tor = tr_torrentInit( h, torrentPath, NULL, 0, &error ) ) )
     157    if( !( tor = tr_torrentInit( h, torrentPath, ".", NULL, 0, &error ) ) )
    158158    {
    159159        printf( "Failed opening torrent file `%s'\n", torrentPath );
     
    228228    tr_natTraversalEnable( h, natTraversal );
    229229   
    230     tr_torrentSetFolder( tor, "." );
    231230    tr_torrentStart( tor );
    232231
     
    247246        s = tr_torrentStat( tor );
    248247
    249         if( s->status & TR_STATUS_PAUSE )
    250         {
    251             break;
    252         }
    253         else if( s->status & TR_STATUS_CHECK_WAIT )
     248        if( s->status & TR_STATUS_CHECK_WAIT )
    254249        {
    255250            chars = snprintf( string, sizeof string,
  • trunk/gtk/main.c

    r2185 r2202  
    957957{
    958958    TrTorrent * gtor = NULL;
    959     int status = 0;
    960     tr_torrent_t * tor;
    961     gtk_tree_model_get( model, iter, MC_TORRENT, &gtor, MC_STAT, &status, -1 );
    962     tor = tr_torrent_handle( gtor );
    963     if( status & TR_STATUS_ACTIVE )
    964         tr_torrentStop( tor );
    965     tr_torrentRemoveFastResume( tor );
    966     tr_torrentStart( tor );
     959    gtk_tree_model_get( model, iter, MC_TORRENT, &gtor, -1 );
     960    tr_torrentRecheck( tr_torrent_handle( gtor ) );
    967961    g_object_unref( G_OBJECT( gtor ) );
    968962}
  • trunk/gtk/tr_core.c

    r2149 r2202  
    3232#include "transmission.h"
    3333
    34 /* XXX */
    35 #define TR_WANT_TORRENT_PRIVATE
    36 
    3734#include "conf.h"
    3835#include "tr_core.h"
     
    5653static void
    5754tr_core_dispose( GObject * obj );
    58 static int
    59 tr_core_check_torrents( TrCore * self );
    60 static int
    61 tr_core_check_zombies( TrCore * self );
    6255static void
    6356tr_core_insert( TrCore * self, TrTorrent * tor );
     
    239232    self->model    = GTK_TREE_MODEL( store );
    240233    self->handle   = tr_init( "gtk" );
    241     self->zombies  = NULL;
    242234    self->nextid   = 1;
    243235    self->quitting = FALSE;
     
    251243    GObjectClass * parent;
    252244    GtkTreeIter    iter;
    253     GList        * ii;
    254245    TrTorrent    * tor;
    255246
     
    274265    g_object_unref( self->model );
    275266
    276     /* sever and unref all remaining zombie torrents */
    277     if( NULL != self->zombies )
    278     {
    279         for( ii = g_list_first( self->zombies ); NULL != ii; ii = ii->next )
    280         {
    281             tr_torrent_sever( ii->data );
    282             g_object_unref( ii->data );
    283         }
    284         g_list_free( self->zombies );
    285     }
    286 
    287267#ifdef REFDBG
    288268    fprintf( stderr, "core    %p dead\n", self );
     
    323303{
    324304    GtkTreeIter iter;
    325     TrTorrent * tor;
    326305
    327306    TR_IS_CORE( self );
    328307
    329308    if( self->disposed )
    330     {
    331309        return;
    332     }
    333310
    334311    g_assert( !self->quitting );
     
    336313
    337314    /* try to stop all the torrents nicely */
    338     if( gtk_tree_model_get_iter_first( self->model, &iter) )
    339     {
    340         do
    341         {
    342             gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
    343             tr_torrent_stop( tor );
    344             g_object_unref( tor );
    345         }
    346         while( gtk_tree_model_iter_next( self->model, &iter ) );
    347     }
     315    if ( gtk_tree_model_get_iter_first( self->model, &iter) ) do {
     316        TrTorrent * tor;
     317        gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
     318        tr_torrent_sever( tor );
     319        g_object_unref( tor );
     320    } while( gtk_list_store_remove( GTK_LIST_STORE(self->model), &iter ) );
    348321
    349322    /* shut down nat traversal */
     
    354327tr_core_quiescent( TrCore * self )
    355328{
    356     tr_handle_status_t * hstat;
     329    const tr_handle_status_t * hstat;
    357330
    358331    TR_IS_CORE( self );
     
    360333
    361334    if( self->disposed )
    362     {
    363335        return TRUE;
    364     }
    365 
    366     if( 0 < tr_core_check_torrents( self ) )
    367     {
     336
     337    if ( tr_torrentCount( self->handle ) != 0 )
    368338        return FALSE;
    369     }
    370339
    371340    hstat = tr_handleStatus( self->handle );
    372 
    373341    return TR_NAT_TRAVERSAL_DISABLED == hstat->natTraversalStatus;
    374342}
     
    377345tr_core_check_torrents( TrCore * self )
    378346{
    379     GtkTreeIter iter;
    380     tr_stat_t * st;
    381     int         count;
    382     TrTorrent * tor;
    383 
    384     g_assert( !self->disposed && self->quitting );
    385 
    386     count = 0;
    387 
    388     if( gtk_tree_model_get_iter_first( self->model, &iter) )
    389     {
    390         do
    391         {
    392             gtk_tree_model_get( self->model, &iter, MC_TORRENT, &tor, -1 );
    393             st = tr_torrent_stat( tor );
    394             if( !( TR_STATUS_PAUSE & st->status ) )
    395             {
    396                 count++;
    397             }
    398             g_object_unref( tor );
    399         }
    400         while( gtk_tree_model_iter_next( self->model, &iter ) );
    401     }
    402 
    403     count += tr_core_check_zombies( self );
    404 
    405     return count;
    406 }
    407 
    408 int
    409 tr_core_check_zombies( TrCore * self )
    410 {
    411     GList     * ii, * next;
    412     tr_stat_t * st;
    413 
    414     for( ii = g_list_first( self->zombies ); NULL != ii; ii = next )
    415     {
    416         next = ii->next;
    417         st = tr_torrent_stat( ii->data );
    418         if( TR_STATUS_PAUSE & st->status )
    419         {
    420             tr_torrent_sever( ii->data );
    421             g_object_unref( ii->data );
    422             /* XXX is this safe to do? */
    423             self->zombies = g_list_delete_link( self->zombies, ii );
    424         }
    425     }
    426 
    427     return g_list_length( self->zombies );
     347    return gtk_tree_model_iter_n_children( self->model, NULL );
    428348}
    429349
     
    667587{
    668588    TrTorrent * tor;
    669     tr_stat_t * st;
    670589
    671590    TR_IS_CORE( self );
    672591
    673592    gtk_tree_model_get( self->model, iter, MC_TORRENT, &tor, -1 );
    674 
    675593    gtk_list_store_remove( GTK_LIST_STORE( self->model ), iter );
     594
    676595    if( TR_FLAG_SAVE & tr_torrent_info( tor )->flags )
    677     {
    678596        tr_torrentRemoveSaved( tr_torrent_handle( tor ) );
    679     }
    680 
    681     st = tr_torrent_stat( tor );
    682     if( TR_STATUS_ACTIVE & st->status )
    683     {
    684         tr_torrentStop( tr_torrent_handle( tor ) );
    685         self->zombies = g_list_append( self->zombies, tor );
    686     }
    687     else
    688     {
    689         tr_torrent_sever( tor );
    690         g_object_unref( tor );
    691     }
     597
     598    tr_torrent_sever( tor );
    692599}
    693600
     
    716623    GtkTreeIter iter;
    717624    TrTorrent * tor;
    718     tr_stat_t * st;
     625    const tr_stat_t * st;
    719626
    720627    TR_IS_CORE( self );
     
    753660        while( gtk_tree_model_iter_next( self->model, &iter ) );
    754661    }
    755 
    756     if( !self->quitting )
    757     {
    758         tr_core_check_zombies( self );
    759     }
    760662}
    761663
  • trunk/gtk/tr_core.h

    r2149 r2202  
    6161    GtkTreeModel      * model;
    6262    tr_handle_t       * handle;
    63     GList             * zombies;
    6463    int                 nextid;
    6564    gboolean            quitting;
  • trunk/gtk/tr_torrent.c

    r2149 r2202  
    3232#include "bencode.h"
    3333
    34 /* XXX */
    35 #define TR_WANT_TORRENT_PRIVATE
    36 
    3734#include "tr_prefs.h"
    3835#include "tr_torrent.h"
     
    4239  TR_TORRENT_HANDLE = 1,
    4340  TR_TORRENT_DIR,
    44   TR_TORRENT_PAUSED,
    4541};
    4642
     
    5955static void
    6056tr_torrent_set_folder(TrTorrent *tor);
    61 static gboolean
    62 tr_torrent_paused(TrTorrent *tor);
    6357
    6458static gpointer
     
    128122                              G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
    129123  g_object_class_install_property(gobject_class, TR_TORRENT_DIR, pspec);
    130 
    131   pspec = g_param_spec_boolean("paused", "Paused",
    132                                "Is the torrent paused or running", TRUE,
    133                                G_PARAM_READWRITE);
    134   g_object_class_install_property(gobject_class, TR_TORRENT_PAUSED, pspec);
    135124}
    136125
     
    144133
    145134  self->handle = NULL;
     135  self->lastStatTime = 0;
    146136  self->dir = NULL;
    147137  self->delfile = NULL;
     
    175165        tr_torrent_set_folder(self);
    176166      break;
    177     case TR_TORRENT_PAUSED:
    178       g_assert(NULL != self->handle);
    179       if(tr_torrent_paused(self) != g_value_get_boolean(value))
    180         (g_value_get_boolean(value) ? tr_torrentStop : tr_torrentStart)
    181           (self->handle);
    182       break;
    183167    default:
    184168      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
     
    203187                                 tr_torrentGetFolder(self->handle)));
    204188      break;
    205     case TR_TORRENT_PAUSED:
    206       g_value_set_boolean(value, tr_torrent_paused(self));
    207       break;
    208189    default:
    209190      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
     
    226207
    227208  if( !self->severed )
    228   {
    229209      tr_torrent_sever( self );
    230   }
    231210
    232211  g_free (self->delfile);
     
    242221    g_return_if_fail (TR_IS_TORRENT( self ));
    243222
    244     if( self->severed )
    245     {
    246         return;
    247     }
    248 
    249 #ifdef REFDBG
    250     fprintf( stderr, "torrent %p sever\n", self );
    251 #endif
    252 
    253     if( NULL == self->handle )
     223    if( !self->severed )
    254224    {
    255225        self->severed = TRUE;
    256         return;
    257     }
    258 
    259     if( !tr_torrent_paused( self ) )
    260     {
    261         tr_torrentStop( self->handle );
    262     }
    263     tr_torrentClose( self->handle );
    264     self->severed = TRUE;
     226
     227        if( self->handle )
     228            tr_torrentClose( self->handle );
     229    }
    265230}
    266231
    267232tr_torrent_t *
    268 tr_torrent_handle(TrTorrent *tor) {
    269   TR_IS_TORRENT(tor);
    270 
    271   if(tor->severed)
    272     return NULL;
    273 
    274   return tor->handle;
    275 }
    276 
    277 tr_stat_t *
    278 tr_torrent_stat(TrTorrent *tor) {
    279   TR_IS_TORRENT(tor);
    280 
    281   if(tor->severed)
    282     return NULL;
    283 
    284   return tr_torrentStat(tor->handle);
     233tr_torrent_handle(TrTorrent *tor)
     234{
     235    g_assert( TR_IS_TORRENT(tor) );
     236
     237    return tor->severed ? NULL : tor->handle;
     238}
     239
     240const tr_stat_t *
     241tr_torrent_stat(TrTorrent *tor)
     242{
     243    const time_t now = time( NULL );
     244
     245    g_assert( TR_IS_TORRENT(tor) );
     246
     247    if( tor->severed )
     248        return NULL;
     249
     250    if( tor->lastStatTime != now ) {
     251        tor->lastStatTime = now;
     252        tor->stat = *tr_torrentStat( tor->handle );
     253    }
     254
     255    return &tor->stat;
    285256}
    286257
     
    300271    TR_IS_TORRENT( self );
    301272
    302     if( self->severed || !tr_torrent_paused( self ) )
    303     {
    304         return;
    305     }
    306 
    307     tr_torrentStart( self->handle );
     273    if( !self->severed )
     274        tr_torrentStart( self->handle );
    308275}
    309276
     
    313280    TR_IS_TORRENT( self );
    314281
    315     if( self->severed || tr_torrent_paused( self ) )
    316     {
    317         return;
    318     }
    319 
    320     tr_torrentStop( self->handle );
     282    if( !self->severed )
     283        tr_torrentStop( self->handle );
    321284}
    322285
    323286static TrTorrent *
    324 maketorrent( tr_torrent_t * handle,
    325              const char   * dir,
    326              gboolean       paused )
    327 {
    328     TrTorrent * tor;
    329 
     287maketorrent( tr_torrent_t * handle )
     288{
    330289    tr_torrentDisablePex( handle,
    331290                          !tr_prefs_get_bool_with_default( PREF_ID_PEX ) );
    332291
    333     tor = g_object_new( TR_TORRENT_TYPE,
    334                         "torrent-handle", handle,
    335                         "download-directory", dir,
    336                         NULL);
    337     g_object_set( tor, "paused", paused, NULL );
    338 
    339     return tor;
     292    return g_object_new( TR_TORRENT_TYPE,
     293                         "torrent-handle", handle,
     294                         NULL);
    340295}
    341296
     
    346301  TrTorrent *ret;
    347302  tr_torrent_t *handle;
    348   int errcode, flag;
     303  int errcode, flags;
    349304
    350305  g_assert(NULL != dir);
     
    352307  *err = NULL;
    353308
    354   flag    = ( TR_TOR_COPY == act || TR_TOR_MOVE == act ? TR_FLAG_SAVE : 0 );
    355309  errcode = -1;
    356310
    357   handle = tr_torrentInit( back, torrent, NULL, flag, &errcode );
     311  flags = ( TR_TOR_COPY == act || TR_TOR_MOVE == act ? TR_FLAG_SAVE : 0 );
     312  if( paused )
     313      flags |= TR_FLAG_PAUSED;
     314
     315  handle = tr_torrentInit( back, torrent, dir, NULL, flags, &errcode );
    358316
    359317  if(NULL == handle) {
     
    372330  }
    373331
    374   ret = maketorrent( handle, dir, paused );
     332  ret = maketorrent( handle );
    375333
    376334  if( TR_TOR_MOVE == act )
     
    386344    tr_torrent_t * handle;
    387345    int            errcode;
     346    int            flags;
    388347
    389348    g_assert( NULL != dir );
     
    391350    *err = NULL;
    392351
     352    flags = TR_FLAG_SAVE;
     353    if( paused )
     354        flags |= TR_FLAG_PAUSED;
     355
    393356    errcode = -1;
    394     handle  = tr_torrentInitData( back, data, size, NULL, TR_FLAG_SAVE,
    395                                   &errcode );
     357    handle  = tr_torrentInitData( back, data, size, dir, NULL, flags, &errcode );
    396358
    397359    if( NULL == handle )
     
    412374    }
    413375
    414     return maketorrent( handle, dir, paused );
     376    return maketorrent( handle );
    415377}
    416378
     
    422384  tr_torrent_t * handle;
    423385  int ii, errcode;
     386  int flags;
    424387  benc_val_t *name, *data;
    425388  char *torrent, *hash, *dir;
     
    464427    return NULL;
    465428
     429  flags = 0;
     430  if( forcedpause )
     431      flags |= TR_FLAG_PAUSED;
     432
    466433  if( NULL != hash )
    467     handle = tr_torrentInitSaved(back, hash, 0, &errcode);
     434    handle = tr_torrentInitSaved(back, hash, dir, flags, &errcode);
    468435  else
    469     handle = tr_torrentInit(back, torrent, NULL, 0, &errcode);
     436    handle = tr_torrentInit(back, torrent, dir, NULL, flags, &errcode);
    470437
    471438  if(NULL == handle) {
     
    485452  }
    486453
    487   ret = maketorrent( handle, dir, paused || forcedpause );
     454  ret = maketorrent( handle );
    488455  ret->ul_cap = ul_cap;
    489456  ret->ul_cap_enabled = ul_cap_enabled;
     
    527494    tr_bencInitStr( tr_bencDictAdd( state, "dir" ),
    528495                    tr_torrentGetFolder( tor->handle ), -1, 1 );
     496#if 0
    529497    tr_bencInitInt( tr_bencDictAdd( state, "paused" ),
    530498                    tr_torrent_paused( tor ) ? 1 : 0 );
     499#endif
    531500
    532501    tr_bencInitInt( tr_bencDictAdd( state, "ul-cap-speed" ),
     
    577546}
    578547
    579 static gboolean
    580 tr_torrent_paused(TrTorrent *tor) {
    581   tr_stat_t *st = tr_torrentStat(tor->handle);
    582 
    583   return (TR_STATUS_INACTIVE & st->status ? TRUE : FALSE);
    584 }
    585 
    586548extern void tr_setUseCustomUpload( tr_torrent_t * tor, int limit );
    587549extern void tr_setUseCustomDownload( tr_torrent_t * tor, int limit );
     
    623585void
    624586tr_torrent_check_seeding_cap ( TrTorrent *gtor) {
    625   tr_stat_t * st = tr_torrent_stat( gtor );
     587  const tr_stat_t * st = tr_torrent_stat( gtor );
    626588  if ((gtor->seeding_cap_enabled) && (st->ratio >= gtor->seeding_cap))
    627589    tr_torrent_stop (gtor);
     
    643605    char * top = 0;
    644606
    645     tr_stat_t * st = tr_torrent_stat( gtor );
     607    const tr_stat_t * st = tr_torrent_stat( gtor );
    646608
    647609    const int tpeers = MAX (st->peersTotal, 0);
     
    649611    const int eta = st->eta;
    650612    const double prog = st->percentDone * 100.0; /* [0...100] */
    651     const int status = st->status;
    652 
    653     if( TR_STATUS_CHECK_WAIT & status )
    654     {
    655         top = g_strdup_printf( _("Waiting to check existing files (%.1f%%)"), prog );
    656     }
    657     else if( TR_STATUS_CHECK & status )
    658     {
    659         top = g_strdup_printf( _("Checking existing files (%.1f%%)"), prog );
    660     }
    661     else if( TR_STATUS_DOWNLOAD & status )
    662     {
    663         if( 0 > eta )
    664         {
    665             top = g_strdup_printf( _("Stalled (%.1f%%)"), prog );
    666         }
    667         else
    668         {
    669             char * timestr = readabletime(eta);
    670             top = g_strdup_printf( _("Finishing in %s (%.1f%%)"),
    671                                    timestr, prog );
    672             g_free(timestr);
    673         }
    674     }
    675     else if( TR_STATUS_SEED & status )
    676     {
    677         top = g_strdup_printf(
    678             ngettext( "Seeding, uploading to %d of %d peer",
    679                       "Seeding, uploading to %d of %d peers", tpeers ),
    680             upeers, tpeers );
    681     }
    682     else if( TR_STATUS_DONE & status )
    683     {
    684         top = g_strdup_printf(
    685             ngettext( "Uploading to %d of %d peer",
    686                       "Uploading to %d of %d peers", tpeers ),
    687             upeers, tpeers );
    688     }
    689     else if( TR_STATUS_STOPPING & status )
    690     {
    691         top = g_strdup( _("Stopping...") );
    692     }
    693     else if( TR_STATUS_PAUSE & status )
    694     {
    695         top = g_strdup_printf( _("Stopped (%.1f%%)"), prog );
    696     }
    697     else
    698     {
    699         top = g_strdup( "" );
    700         g_assert_not_reached();
     613
     614    switch( st->status )
     615    {
     616        case TR_STATUS_CHECK_WAIT:
     617            top = g_strdup_printf( _("Waiting to check existing files (%.1f%%)"), prog );
     618            break;
     619
     620        case TR_STATUS_CHECK:
     621            top = g_strdup_printf( _("Checking existing files (%.1f%%)"), prog );
     622            break;
     623
     624        case TR_STATUS_DOWNLOAD:
     625            if( eta < 0 )
     626                top = g_strdup_printf( _("Stalled (%.1f%%)"), prog );
     627            else {
     628                char * timestr = readabletime(eta);
     629                top = g_strdup_printf( _("Finishing in %s (%.1f%%)"), timestr, prog );
     630                g_free(timestr);
     631            }
     632            break;
     633
     634        case TR_STATUS_DONE:
     635            top = g_strdup_printf(
     636                ngettext( "Uploading to %d of %d peer",
     637                          "Uploading to %d of %d peers", tpeers ),
     638                          upeers, tpeers );
     639            break;
     640
     641        case TR_STATUS_SEED:
     642            top = g_strdup_printf(
     643                ngettext( "Seeding, uploading to %d of %d peer",
     644                          "Seeding, uploading to %d of %d peers", tpeers ),
     645                          upeers, tpeers );
     646            break;
     647
     648        case TR_STATUS_STOPPING:
     649            top = g_strdup( _("Stopping...") );
     650            break;
     651
     652        case TR_STATUS_STOPPED:
     653            top = g_strdup( _("Stopped") );
     654            break;
     655
     656        default:
     657            top = g_strdup_printf("Unrecognized state: %d", st->status );
     658            break;
     659
    701660    }
    702661
  • trunk/gtk/tr_torrent.h

    r1998 r2202  
    5959  char *dir;
    6060  char *delfile;
     61  tr_stat_t stat;
     62  time_t lastStatTime;
    6163
    6264  /* FIXME: hm, are these heavyweight enough to deserve their own properties? */
     
    8183tr_torrent_handle(TrTorrent *tor);
    8284
    83 tr_stat_t *
     85const tr_stat_t *
    8486tr_torrent_stat(TrTorrent *tor);
    8587
     
    113115tr_torrent_set_seeding_cap_enabled ( TrTorrent*, gboolean );
    114116
    115 #ifdef TR_WANT_TORRENT_PRIVATE
    116 
    117117TrTorrent *
    118118tr_torrent_new( tr_handle_t * handle, const char * path, const char * dir,
     
    136136tr_torrent_sever( TrTorrent * tor );
    137137
    138 #endif /* TR_WANT_TORRENT_PRIVATE */
    139 
    140138#endif
  • trunk/libtransmission/choking.c

    r2149 r2202  
    146146    for( tor = c->h->torrentList; tor; tor = tor->next )
    147147    {
    148         tr_lockLock( &tor->lock );
     148        tr_torrentWriterLock( tor );
    149149        peersTotalCount += tor->peerCount;
    150150    }
     
    311311    /* Unlock all torrents */
    312312    for( tor = c->h->torrentList; tor; tor = tor->next )
    313     {
    314         tr_lockUnlock( &tor->lock );
    315     }
     313        tr_torrentWriterUnlock( tor );
    316314
    317315    tr_lockUnlock( &c->lock );
  • trunk/libtransmission/fastresume.c

    r2185 r2202  
    212212        const tr_time_t * oldMTimes = (const tr_time_t *) walk;
    213213        for( i=0; i<n; ++i ) {
    214             if ( !curMTimes[i] || ( curMTimes[i]!=oldMTimes[i] ) ) {
     214            if ( curMTimes[i]!=oldMTimes[i] ) {
    215215                const tr_file_t * file = &tor->info.files[i];
    216216                tr_dbg( "File '%s' mtimes differ-- flagging pieces [%d..%d] for recheck",
  • trunk/libtransmission/inout.c

    r2185 r2202  
    1515{
    1616    tr_torrent_t * tor;
    17 
    18     tr_bitfield_t * uncheckedPieces;
    1917};
    2018
     
    136134    assert( buflen <= (size_t) tr_pieceSize( pieceIndex ) );
    137135
    138     /* Release the torrent lock so the UI can still update itself if
    139        this blocks for a while */
    140     tr_lockUnlock( &tor->lock );
    141 
    142136    findFileLocation ( tor, pieceIndex, pieceOffset, &fileIndex, &fileOffset );
    143137
     
    159153    }
    160154
    161     tr_lockLock( &tor->lock );
    162 
    163155    return ret;
    164156}
     
    218210}
    219211
    220 static void
    221 checkFiles( tr_io_t * io )
     212int
     213tr_ioCheckFiles( tr_torrent_t * tor, int mode )
    222214{
    223215    int i;
    224     tr_torrent_t * tor = io->tor;
    225 
    226     tr_bitfieldClear( io->uncheckedPieces );
    227 
    228     if( fastResumeLoad( io->tor, io->uncheckedPieces ) )
    229         tr_bitfieldAddRange( io->uncheckedPieces, 0, tor->info.pieceCount-1 );
    230 
    231     if( !tr_bitfieldIsEmpty( io->uncheckedPieces ) )
    232         tr_inf( "Rechecking portions of \"%s\"", tor->info.name );
     216    tr_bitfield_t * uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
     217
     218    tr_cpReset( tor->completion );
     219
     220    tr_bitfieldClear( uncheckedPieces );
     221
     222    if( (mode==TR_RECHECK_FORCE) || fastResumeLoad( tor, uncheckedPieces ) )
     223        tr_bitfieldAddRange( uncheckedPieces, 0, tor->info.pieceCount-1 );
     224
     225    if( tr_bitfieldIsEmpty( uncheckedPieces ) ) {
     226        tr_bitfieldFree( uncheckedPieces );
     227        return TR_OK;
     228    }
     229
     230    if( mode == TR_RECHECK_FAST ) {
     231        tr_bitfieldFree( uncheckedPieces );
     232        return TR_ERROR_IO_OTHER;
     233    }
     234
     235    tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
    233236
    234237    for( i=0; i<tor->info.pieceCount; ++i )
    235238    {
    236         if( tor->status & TR_STATUS_STOPPING )
    237             break;
    238 
    239         if( !tr_bitfieldHas( io->uncheckedPieces, i ) )
     239        if( !tr_bitfieldHas( uncheckedPieces, i ) )
    240240            continue;
    241241
    242242        tr_dbg ( "Checking piece %d because it's not in fast-resume", i );
    243243
    244         if( !checkPiece( tor, i ) )
    245            tr_cpPieceAdd( tor->completion, i );
    246         else
    247            tr_cpPieceRem( tor->completion, i );
    248 
    249         tr_bitfieldRem( io->uncheckedPieces, i );
    250     }
     244        tr_torrentSetHasPiece( tor, i, !checkPiece( tor, i ) );
     245
     246        tr_bitfieldRem( uncheckedPieces, i );
     247    }
     248
     249    fastResumeSave( tor );
     250    tr_bitfieldFree( uncheckedPieces );
     251    return TR_OK;
    251252}
    252253
     
    256257
    257258tr_io_t*
    258 tr_ioInit( tr_torrent_t * tor )
    259 {
    260     tr_io_t * io = calloc( 1, sizeof( tr_io_t ) );
    261     io->uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
     259tr_ioInitFast( tr_torrent_t * tor )
     260{
     261    tr_io_t * io = tr_calloc( 1, sizeof( tr_io_t ) );
    262262    io->tor = tor;
    263     checkFiles( io );
     263
     264    if( tr_ioCheckFiles( tor, TR_RECHECK_FAST ) )
     265    {
     266        tr_free( io );
     267        io = NULL;
     268    }
     269
    264270    return io;
    265271}
     272
    266273
    267274void
    268275tr_ioSync( tr_io_t * io )
    269276{
    270     int i;
    271     const tr_info_t * info = &io->tor->info;
    272 
    273     for( i=0; i<info->fileCount; ++i )
    274         tr_fdFileClose( io->tor->destination, info->files[i].name );
    275 
    276     if( tr_bitfieldIsEmpty( io->uncheckedPieces ) )
     277    if( io != NULL )
     278    {
     279        int i;
     280        const tr_info_t * info = &io->tor->info;
     281
     282        for( i=0; i<info->fileCount; ++i )
     283            tr_fdFileClose( io->tor->destination, info->files[i].name );
     284
    277285        fastResumeSave( io->tor );
     286    }
    278287}
    279288
     
    281290tr_ioClose( tr_io_t * io )
    282291{
    283     tr_ioSync( io );
    284 
    285     tr_bitfieldFree( io->uncheckedPieces );
    286     free( io );
     292    if( io != NULL )
     293    {
     294        tr_ioSync( io );
     295        tr_free( io );
     296    }
    287297}
    288298
    289299
    290300/* try to load the fast resume file */
    291 void
     301int
    292302tr_ioLoadResume( tr_torrent_t * tor )
    293303{
    294     tr_io_t * io = calloc( 1, sizeof( tr_io_t ) );
    295     io->uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
    296     io->tor = tor;
    297     fastResumeLoad( tor, io->uncheckedPieces );
    298     tor->ioLoaded = 1;
    299     tr_bitfieldFree( io->uncheckedPieces );
    300     free( io );
     304    return tr_ioCheckFiles ( tor, TR_RECHECK_FAST );
    301305}
    302306
  • trunk/libtransmission/inout.h

    r1822 r2202  
    2828typedef struct tr_io_s tr_io_t;
    2929
    30 void      tr_ioLoadResume  ( tr_torrent_t * );
    31 void      tr_ioRemoveResume( tr_torrent_t * tor );
     30int       tr_ioLoadResume  ( tr_torrent_t * );
     31void      tr_ioRemoveResume( tr_torrent_t * );
    3232
    33 tr_io_t * tr_ioInit        ( tr_torrent_t * );
     33
     34enum
     35{
     36  TR_RECHECK_FAST,  /* only try the fast resume, even if it's incomplete */
     37  TR_RECHECK_FORCE  /* ignore the fast resume data; recheck from disk */
     38};
     39int tr_ioCheckFiles  ( tr_torrent_t *, int recheckMode );
     40
     41
     42tr_io_t * tr_ioInitFast        ( tr_torrent_t * );
    3443
    3544/***********************************************************************
  • trunk/libtransmission/internal.h

    r2149 r2202  
    158158#endif
    159159
     160void tr_torrentResetTransferStats( tr_torrent_t * );
     161
    160162int tr_torrentAddCompact( tr_torrent_t * tor, int from,
    161163                           uint8_t * buf, int count );
    162164int tr_torrentAttachPeer( tr_torrent_t * tor, tr_peer_t * peer );
     165
     166void tr_torrentSetHasPiece( tr_torrent_t * tor, int pieceIndex, int has );
     167
     168void tr_torrentReaderLock    ( const tr_torrent_t * );
     169void tr_torrentReaderUnlock  ( const tr_torrent_t * );
     170void tr_torrentWriterLock    ( tr_torrent_t * );
     171void tr_torrentWriterUnlock  ( tr_torrent_t * );
     172
     173typedef enum
     174{
     175    TR_RUN_CHECKING  = (1<<0), /* checking files' checksums */
     176    TR_RUN_RUNNING   = (1<<1), /* seeding or leeching */
     177    TR_RUN_STOPPING  = (1<<2), /* stopping */
     178    TR_RUN_STOPPED   = (1<<3)  /* stopped */
     179}
     180run_status_t;
    163181
    164182struct tr_torrent_s
     
    173191    tr_ratecontrol_t * swarmspeed;
    174192
    175     int               status;
    176193    int               error;
    177194    char              errorString[128];
     
    195212    tr_completion_t * completion;
    196213
    197     volatile char     die;
     214    volatile char     dieFlag;
     215    volatile char     recheckFlag;
     216    run_status_t      runStatus;
     217    cp_status_t       cpStatus;
    198218    tr_thread_t       thread;
    199     tr_lock_t         lock;
    200     tr_cond_t         cond;
     219    tr_rwlock_t       lock;
    201220
    202221    tr_tracker_t    * tracker;
     
    220239    int               statCur;
    221240
    222     tr_torrent_t    * prev;
    223241    tr_torrent_t    * next;
    224242};
  • trunk/libtransmission/peer.c

    r2184 r2202  
    6060 * all of our peers.  This too helps prevent gridlock.
    6161 */
    62 static const double SWIFT_LARGESSE = 0.05; /* 5% of our UL */
     62static const double SWIFT_LARGESSE = 0.10; /* 10% of our UL */
    6363
    6464/**
     
    451451    /* Disconnect if seeder and torrent is seeding */
    452452    if(   ( peer->progress >= 1.0 )
    453        && ( peer->tor->status & (TR_STATUS_SEED|TR_STATUS_DONE) ) )
     453       && ( peer->tor->cpStatus != TR_CP_INCOMPLETE ) )
    454454    {
    455455        return TR_ERROR;
     
    837837    tr_peer_t ** deadbeats;
    838838
    839     tr_lockLock( &tor->lock );
     839    tr_torrentWriterLock( tor );
    840840
    841841    deadbeats = tr_calloc( tor->peerCount, sizeof(tr_peer_t*) );
     
    865865    free( deadbeats );
    866866
    867     tr_lockUnlock( &tor->lock );
     867    tr_torrentWriterUnlock( tor );
    868868}
    869869void
  • trunk/libtransmission/platform.c

    r2197 r2202  
    201201{
    202202    tr_thread_t * t = _t;
     203    char* name = tr_strdup( t->name );
    203204
    204205#ifdef SYS_BEOS
     
    208209#endif
    209210
    210     tr_dbg( "Thread '%s' started", t->name );
     211    tr_dbg( "Thread '%s' started", name );
    211212    t->func( t->arg );
    212     tr_dbg( "Thread '%s' exited", t->name );
     213    tr_dbg( "Thread '%s' exited", name );
     214    tr_free( name );
    213215}
    214216
     
    242244#endif
    243245        tr_dbg( "Thread '%s' joined", t->name );
    244         free( t->name );
     246        tr_free( t->name );
    245247        t->name = NULL;
    246248        t->func = NULL;
     
    271273    #error how is this done in beos
    272274#else
     275    /* success on zero! */
    273276    return pthread_mutex_trylock( l );
    274277#endif
  • trunk/libtransmission/shared.c

    r2177 r2202  
    321321    for( tor = h->torrentList; tor; tor = tor->next )
    322322    {
    323         tr_lockLock( &tor->lock );
     323        tr_torrentWriterLock( tor );
    324324        tor->publicPort = port;
    325         tr_lockUnlock( &tor->lock );
     325        tr_torrentWriterUnlock( tor );
    326326    }
    327327}
     
    404404            for( tor = h->torrentList; tor; tor = tor->next )
    405405            {
    406                 tr_lockLock( &tor->lock );
    407                 if( tor->status & TR_STATUS_INACTIVE )
     406                tr_torrentWriterLock( tor );
     407                if( tor->cpStatus != TR_RUN_RUNNING )
    408408                {
    409                     tr_lockUnlock( &tor->lock );
     409                    tr_torrentWriterUnlock( tor );
    410410                    continue;
    411411                }
    412412
    413                 if( 0 == memcmp( tor->info.hash, hash,
    414                             SHA_DIGEST_LENGTH ) )
     413                if( !memcmp( tor->info.hash, hash, SHA_DIGEST_LENGTH ) )
    415414                {
    416415                    /* Found it! */
    417416                    tr_torrentAttachPeer( tor, s->peers[ii] );
    418                     tr_lockUnlock( &tor->lock );
     417                    tr_torrentWriterUnlock( tor );
    419418                    goto removePeer;
    420419                }
    421                 tr_lockUnlock( &tor->lock );
     420                tr_torrentWriterUnlock( tor );
    422421            }
    423422
  • trunk/libtransmission/torrent.c

    r2185 r2202  
    2727#define INTERVAL_MSEC 100
    2828
    29 /***********************************************************************
    30  * Local prototypes
    31  **********************************************************************/
    32 static tr_torrent_t * torrentRealInit( tr_handle_t *, tr_torrent_t * tor,
    33                                        uint8_t *, int flags, int * error );
    34 static void torrentReallyStop( tr_torrent_t * );
    35 
    36 static void ioInitAdd ( tr_torrent_t * );
    37 static int ioInitRemove ( tr_torrent_t * );
    38 static void downloadLoop( void * );
    39 
    40 void tr_setUseCustomUpload( tr_torrent_t * tor, int limit )
    41 {
     29/***
     30****  LOCKS
     31***/
     32
     33void
     34tr_torrentReaderLock( const tr_torrent_t * tor )
     35{
     36    tr_rwReaderLock ( (tr_rwlock_t*)&tor->lock );
     37}
     38
     39void
     40tr_torrentReaderUnlock( const tr_torrent_t * tor )
     41{
     42    tr_rwReaderUnlock ( (tr_rwlock_t*)&tor->lock );
     43}
     44
     45void
     46tr_torrentWriterLock( tr_torrent_t * tor )
     47{
     48    tr_rwWriterLock ( &tor->lock );
     49}
     50
     51void
     52tr_torrentWriterUnlock( tr_torrent_t * tor )
     53{
     54    tr_rwWriterUnlock ( &tor->lock );
     55}
     56
     57/***
     58****  PER-TORRENT UL / DL SPEEDS
     59***/
     60
     61void
     62tr_setUseCustomUpload( tr_torrent_t * tor, int limit )
     63{
     64    tr_torrentWriterLock( tor );
    4265    tor->customUploadLimit = limit;
    43 }
    44 
    45 void tr_setUseCustomDownload( tr_torrent_t * tor, int limit )
    46 {
     66    tr_torrentWriterUnlock( tor );
     67}
     68
     69void
     70tr_setUseCustomDownload( tr_torrent_t * tor, int limit )
     71{
     72    tr_torrentWriterLock( tor );
    4773    tor->customDownloadLimit = limit;
    48 }
    49 
    50 void tr_setUploadLimit( tr_torrent_t * tor, int limit )
    51 {
     74    tr_torrentWriterUnlock( tor );
     75}
     76
     77void
     78tr_setUploadLimit( tr_torrent_t * tor, int limit )
     79{
     80    tr_torrentWriterLock( tor );
    5281    tr_rcSetLimit( tor->upload, limit );
    53 }
    54 
    55 void tr_setDownloadLimit( tr_torrent_t * tor, int limit )
    56 {
     82    tr_torrentWriterUnlock( tor );
     83}
     84
     85void
     86tr_setDownloadLimit( tr_torrent_t * tor, int limit )
     87{
     88    tr_torrentWriterLock( tor );
    5789    tr_rcSetLimit( tor->download, limit );
    58 }
    59 
    60 tr_torrent_t *
    61 tr_torrentInit( tr_handle_t * h, const char * path,
    62                 uint8_t * hash, int flags, int * error )
    63 {
    64     tr_torrent_t * tor;
    65 
    66     tor  = calloc( 1, sizeof *tor );
    67     if( NULL == tor )
    68     {
    69         *error = TR_EOTHER;
    70         return NULL;
    71     }
    72 
    73     /* Parse torrent file */
    74     if( tr_metainfoParseFile( &tor->info, h->tag, path,
    75                               TR_FLAG_SAVE & flags ) )
    76     {
    77         *error = TR_EINVALID;
    78         free( tor );
    79         return NULL;
    80     }
    81 
    82     return torrentRealInit( h, tor, hash, flags, error );
    83 }
    84 
    85 tr_torrent_t *
    86 tr_torrentInitData( tr_handle_t * h, uint8_t * data, size_t size,
    87                     uint8_t * hash, int flags, int * error )
    88 {
    89     tr_torrent_t * tor;
    90 
    91     tor  = calloc( 1, sizeof *tor );
    92     if( NULL == tor )
    93     {
    94         *error = TR_EOTHER;
    95         return NULL;
    96     }
    97 
    98     /* Parse torrent file */
    99     if( tr_metainfoParseData( &tor->info, h->tag, data, size,
    100                               TR_FLAG_SAVE & flags ) )
    101     {
    102         *error = TR_EINVALID;
    103         free( tor );
    104         return NULL;
    105     }
    106 
    107     return torrentRealInit( h, tor, hash, flags, error );
    108 }
    109 
    110 tr_torrent_t *
    111 tr_torrentInitSaved( tr_handle_t * h, const char * hashStr,
    112                      int flags, int * error )
    113 {
    114     tr_torrent_t * tor;
    115 
    116     tor  = calloc( 1, sizeof *tor );
    117     if( NULL == tor )
    118     {
    119         *error = TR_EOTHER;
    120         return NULL;
    121     }
    122 
    123     /* Parse torrent file */
    124     if( tr_metainfoParseHash( &tor->info, h->tag, hashStr ) )
    125     {
    126         *error = TR_EINVALID;
    127         free( tor );
    128         return NULL;
    129     }
    130 
    131     return torrentRealInit( h, tor, NULL, ( TR_FLAG_SAVE | flags ), error );
    132 }
    133 
    134 /***********************************************************************
    135  * tr_torrentInit
    136  ***********************************************************************
    137  * Allocates a tr_torrent_t structure, then relies on tr_metainfoParse
    138  * to fill it.
    139  **********************************************************************/
    140 static tr_torrent_t * torrentRealInit( tr_handle_t * h, tr_torrent_t * tor,
    141                                        uint8_t * hash, int flags, int * error )
    142 {
     90    tr_torrentWriterUnlock( tor );
     91}
     92
     93/***
     94****
     95****  TORRENT INSTANTIATION
     96****
     97***/
     98
     99static int
     100tr_torrentDuplicateDownload( tr_torrent_t * tor )
     101{
     102    tr_torrent_t * current;
     103   
     104    /* Check if a torrent with the same name and destination is already active */
     105    for( current = tor->handle->torrentList; current; current = current->next )
     106    {
     107        if( current != tor
     108            && !strcmp( tor->destination, current->destination )
     109            && !strcmp( tor->info.name, current->info.name ) )
     110        {
     111            return TRUE;
     112        }
     113    }
     114    return FALSE;
     115}
     116
     117static int
     118getBytePiece( const tr_info_t * info, uint64_t byteOffset )
     119{
     120    assert( info != NULL );
     121    assert( info->pieceSize != 0 );
     122
     123    return byteOffset / info->pieceSize;
     124}
     125
     126static void
     127initFilePieces ( tr_info_t * info, int fileIndex )
     128{
     129    tr_file_t * file = &info->files[fileIndex];
     130    uint64_t firstByte, lastByte;
     131
     132    assert( info != NULL );
     133    assert( 0<=fileIndex && fileIndex<info->fileCount );
     134
     135    file = &info->files[fileIndex];
     136    firstByte = file->offset;
     137    lastByte = firstByte + (file->length ? file->length-1 : 0);
     138    file->firstPiece = getBytePiece( info, firstByte );
     139    file->lastPiece = getBytePiece( info, lastByte );
     140    tr_dbg( "file #%d is in pieces [%d...%d] (%s)", fileIndex, file->firstPiece, file->lastPiece, file->name );
     141}
     142
     143static tr_priority_t
     144calculatePiecePriority ( const tr_torrent_t * tor,
     145                         int                  piece )
     146{
     147    int i;
     148    tr_priority_t priority = TR_PRI_DND;
     149
     150    for( i=0; i<tor->info.fileCount; ++i )
     151    {
     152        const tr_file_t * file = &tor->info.files[i];
     153        if ( file->firstPiece <= piece
     154          && file->lastPiece  >= piece
     155          && file->priority   >  priority)
     156              priority = file->priority;
     157    }
     158
     159    return priority;
     160}
     161
     162void
     163tr_torrentInitFilePieces( tr_torrent_t * tor )
     164{
     165    int i;
     166    uint64_t offset = 0;
     167
     168    assert( tor != NULL );
     169
     170    for( i=0; i<tor->info.fileCount; ++i ) {
     171      tor->info.files[i].offset = offset;
     172      offset += tor->info.files[i].length;
     173      initFilePieces( &tor->info, i );
     174    }
     175
     176    for( i=0; i<tor->info.pieceCount; ++i )
     177      tor->info.pieces[i].priority = calculatePiecePriority( tor, i );
     178}
     179
     180static void torrentThreadLoop( void * );
     181
     182static tr_torrent_t *
     183torrentRealInit( tr_handle_t   * h,
     184                 tr_torrent_t  * tor,
     185                 const char    * destination,
     186                 uint8_t       * hash,
     187                 int             flags,
     188                 int           * error )
     189{
     190    char name[512];
    143191    tr_torrent_t  * tor_tmp;
    144192    tr_info_t     * inf;
     
    149197
    150198    tr_sharedLock( h->shared );
     199
     200    tor->destination = tr_strdup( destination );
    151201
    152202    /* Make sure this torrent is not already open */
     
    168218    }
    169219
     220    tr_torrentInitFilePieces( tor );
     221
    170222    tor->handle   = h;
    171     tor->status   = TR_STATUS_PAUSE;
    172223    tor->id       = h->id;
    173224    tor->key      = h->key;
    174225    tor->azId     = h->azId;
    175226    tor->hasChangedState = -1;
     227   
     228    /* Don't start if a torrent with the same name
     229       and destination is already active */
     230    if( tr_torrentDuplicateDownload( tor ) )
     231    {
     232        *error = TR_ERROR_IO_DUP_DOWNLOAD;
     233        tr_metainfoFree( &tor->info );
     234        free( tor );
     235        tr_sharedUnlock( h->shared );
     236        return NULL;
     237    }
    176238
    177239    /* Escaped info hash for HTTP queries */
     
    192254
    193255    tor->thread = THREAD_EMPTY;
    194     tr_lockInit( &tor->lock );
    195     tr_condInit( &tor->cond );
     256    tr_rwInit( &tor->lock );
    196257
    197258    tor->upload         = tr_rcInit();
     
    201262    /* We have a new torrent */
    202263    tor->publicPort = tr_sharedGetPublicPort( h->shared );
    203     tor->prev       = NULL;
    204     tor->next       = h->torrentList;
    205     if( tor->next )
    206     {
    207         tor->next->prev = tor;
    208     }
    209     h->torrentList = tor;
    210     (h->torrentCount)++;
    211264
    212265    tr_sharedUnlock( h->shared );
    213266
    214267    if( !h->isPortSet )
    215     {
    216268        tr_setBindPort( h, TR_DEFAULT_PORT );
    217     }
    218 
    219     tr_torrentInitFilePieces( tor );
    220 
    221     return tor;
    222 }
    223 
    224 tr_info_t * tr_torrentInfo( tr_torrent_t * tor )
    225 {
    226     return &tor->info;
    227 }
    228 
    229 /***********************************************************************
    230  * tr_torrentScrape     
    231  **********************************************************************/
    232 int tr_torrentScrape( tr_torrent_t * tor, int * s, int * l, int * d )
    233 {
    234     return tr_trackerScrape( tor, s, l, d );
    235 }
    236 
    237 void tr_torrentSetFolder( tr_torrent_t * tor, const char * path )
    238 {
    239     tor->destination = strdup( path );
    240     if ( !tor->ioLoaded )
    241     {
    242         tr_ioLoadResume( tor );
    243     }
    244 }
    245 
    246 char * tr_torrentGetFolder( tr_torrent_t * tor )
    247 {
    248     return tor->destination;
    249 }
    250 
    251 int tr_torrentDuplicateDownload( tr_torrent_t * tor )
    252 {
    253     tr_torrent_t * current;
    254    
    255     /* Check if a torrent with the same name and destination is already active */
    256     for( current = tor->handle->torrentList; current; current = current->next )
    257     {
    258         if( current != tor && current->status != TR_STATUS_PAUSE
    259             && !strcmp( tor->destination, current->destination )
    260             && !strcmp( tor->info.name, current->info.name ) )
    261         {
    262             return 1;
    263         }
    264     }
    265     return 0;
    266 }
    267 
    268 void tr_torrentStart( tr_torrent_t * tor )
    269 {
    270     /* Join the thread first */
    271     torrentReallyStop( tor );
    272 
    273     tr_inf("Starting torrent \"%s\"", tor->info.name);
    274    
    275     /* Don't start if a torrent with the same name and destination is already active */
    276     if( tr_torrentDuplicateDownload( tor ) )
    277     {
    278         tor->error = TR_ERROR_IO_DUP_DOWNLOAD;
    279         snprintf( tor->errorString, sizeof( tor->errorString ),
    280                     "%s", tr_errorString( TR_ERROR_IO_DUP_DOWNLOAD ) );
    281         return;
    282     }
    283 
    284     tr_lockLock( &tor->lock );
    285269
    286270    tor->downloadedPrev += tor->downloadedCur;
     
    289273    tor->uploadedCur     = 0;
    290274
    291     tor->status  = TR_STATUS_CHECK_WAIT;
    292275    tor->error   = TR_OK;
    293     tor->tracker = tr_trackerInit( tor );
    294 
    295     tor->startDate = tr_date();
    296     tor->die = 0;
    297     tor->thread = THREAD_EMPTY;
    298 
    299     tr_lockUnlock( &tor->lock );
    300 
    301     ioInitAdd ( tor );
    302 }
    303 
    304 static void torrentStop( tr_torrent_t * tor )
    305 {
    306     tr_inf("Stopping torrent \"%s\"", tor->info.name);
    307     tr_trackerStopped( tor->tracker );
    308     tr_rcReset( tor->download );
    309     tr_rcReset( tor->upload );
    310     tr_rcReset( tor->swarmspeed );
    311     tor->status = TR_STATUS_STOPPING;
    312     tor->stopDate = tr_date();
    313 }
    314 
    315 void tr_torrentStop( tr_torrent_t * tor )
    316 {
    317     tr_lockLock( &tor->lock );
    318     torrentStop( tor );
    319 
    320     /* Don't return until the files are closed, so the UI can trash
    321      * them if requested */
    322     if ( ioInitRemove( tor ) ) /* torrent never got started */
    323         tor->status = TR_STATUS_STOPPED;
    324     else
    325         tr_condWait( &tor->cond, &tor->lock );
    326 
    327     tr_lockUnlock( &tor->lock );
    328 }
     276    tor->runStatus = flags & TR_FLAG_PAUSED ? TR_RUN_STOPPED : TR_RUN_RUNNING;
     277
     278    tr_sharedLock( h->shared );
     279    tor->next = h->torrentList;
     280    h->torrentList = tor;
     281    h->torrentCount++;
     282    tr_sharedUnlock( h->shared );
     283
     284    snprintf( name, sizeof( name ), "torrent %p (%s)", tor, tor->info.name );
     285    tr_threadCreate( &tor->thread, torrentThreadLoop, tor, name );
     286
     287    return tor;
     288}
     289
     290tr_torrent_t *
     291tr_torrentInit( tr_handle_t   * h,
     292                const char    * path,
     293                const char    * destination,
     294                uint8_t       * hash,
     295                int             flags,
     296                int           * error )
     297{
     298    tr_torrent_t * tor  = tr_calloc( 1, sizeof *tor );
     299    if( NULL == tor )
     300    {
     301        *error = TR_EOTHER;
     302        return NULL;
     303    }
     304
     305    /* Parse torrent file */
     306    if( tr_metainfoParseFile( &tor->info, h->tag, path,
     307                              TR_FLAG_SAVE & flags ) )
     308    {
     309        *error = TR_EINVALID;
     310        free( tor );
     311        return NULL;
     312    }
     313
     314    return torrentRealInit( h, tor, destination, hash, flags, error );
     315}
     316
     317tr_torrent_t *
     318tr_torrentInitData( tr_handle_t  * h,
     319                    uint8_t      * data,
     320                    size_t         size,
     321                    const char   * destination,
     322                    uint8_t      * hash,
     323                    int            flags,
     324                    int          * error )
     325{
     326    tr_torrent_t * tor  = tr_calloc( 1, sizeof *tor );
     327    if( NULL == tor )
     328    {
     329        *error = TR_EOTHER;
     330        return NULL;
     331    }
     332
     333    /* Parse torrent file */
     334    if( tr_metainfoParseData( &tor->info, h->tag, data, size,
     335                              TR_FLAG_SAVE & flags ) )
     336    {
     337        *error = TR_EINVALID;
     338        free( tor );
     339        return NULL;
     340    }
     341
     342    return torrentRealInit( h, tor, destination, hash, flags, error );
     343}
     344
     345tr_torrent_t *
     346tr_torrentInitSaved( tr_handle_t  * h,
     347                     const char   * hashStr,
     348                     const char   * destination,
     349                     int            flags,
     350                     int          * error )
     351{
     352    tr_torrent_t * tor  = calloc( 1, sizeof *tor );
     353    if( NULL == tor )
     354    {
     355        *error = TR_EOTHER;
     356        return NULL;
     357    }
     358
     359    /* Parse torrent file */
     360    if( tr_metainfoParseHash( &tor->info, h->tag, hashStr ) )
     361    {
     362        *error = TR_EINVALID;
     363        free( tor );
     364        return NULL;
     365    }
     366
     367    return torrentRealInit( h, tor, destination, NULL, (TR_FLAG_SAVE|flags), error );
     368}
     369
     370tr_info_t * tr_torrentInfo( tr_torrent_t * tor )
     371{
     372    return &tor->info;
     373}
     374
     375/***
     376****
     377***/
     378
     379int tr_torrentScrape( tr_torrent_t * tor, int * s, int * l, int * d )
     380{
     381    return tr_trackerScrape( tor, s, l, d );
     382}
     383
     384void tr_torrentSetFolder( tr_torrent_t * tor, const char * path )
     385{
     386    tr_free( tor->destination );
     387    tor->destination = tr_strdup( path );
     388
     389    if( !tor->ioLoaded )
     390         tor->ioLoaded = tr_ioLoadResume( tor ) == TR_OK;
     391}
     392
     393const char* tr_torrentGetFolder( const tr_torrent_t * tor )
     394{
     395    return tor->destination;
     396}
     397
    329398
    330399/***********************************************************************
     
    333402 * Joins the download thread and frees/closes everything related to it.
    334403 **********************************************************************/
    335 static void torrentReallyStop( tr_torrent_t * tor )
    336 {
    337     int i;
    338 
    339     tor->die = 1;
    340     tr_threadJoin( &tor->thread );
    341 
    342     if( tor->tracker )
    343     {
    344        tr_trackerClose( tor->tracker );
    345        tor->tracker = NULL;
    346     }
    347 
    348     tr_lockLock( &tor->lock );
    349     for( i = 0; i < tor->peerCount; i++ )
    350     {
    351         tr_peerDestroy( tor->peers[i] );
    352     }
    353     tor->peerCount = 0;
    354     tr_lockUnlock( &tor->lock );
    355 }
    356404
    357405void tr_torrentDisablePex( tr_torrent_t * tor, int disable )
    358406{
    359     int ii;
    360 
    361     if( TR_FLAG_PRIVATE & tor->info.flags )
    362     {
    363         return;
    364     }
    365 
    366     tr_lockLock( &tor->lock );
    367 
    368     if( tor->pexDisabled == disable )
    369     {
    370         tr_lockUnlock( &tor->lock );
    371         return;
    372     }
    373 
    374     tor->pexDisabled = disable;
    375     for( ii = 0; ii < tor->peerCount; ii++ )
    376     {
    377         tr_peerSetPrivate( tor->peers[ii], disable );
    378     }
    379 
    380     tr_lockUnlock( &tor->lock );
     407    tr_torrentWriterLock( tor );
     408
     409    if( ! ( TR_FLAG_PRIVATE & tor->info.flags ) )
     410    {
     411        if( tor->pexDisabled != disable )
     412        {
     413            int i;
     414            tor->pexDisabled = disable;
     415            for( i=0; i<tor->peerCount; ++i )
     416                tr_peerSetPrivate( tor->peers[i], disable );
     417        }
     418    }
     419
     420    tr_torrentWriterUnlock( tor );
    381421}
    382422
    383423static int tr_didStateChangeTo ( tr_torrent_t * tor, int status )
    384424{
    385     if( tor->hasChangedState == status )
    386     {
     425    int ret;
     426
     427    tr_torrentWriterLock( tor );
     428    if (( ret = tor->hasChangedState == status ))
    387429        tor->hasChangedState = -1;
    388         return 1;
    389     }
    390     return 0;
     430    tr_torrentWriterUnlock( tor );
     431
     432    return ret;
    391433}
    392434
     
    404446}
    405447
    406 void tr_manualUpdate( tr_torrent_t * tor )
    407 {
     448void tr_manualUpdate( tr_torrent_t * tor UNUSED )
     449{
     450#if 0
    408451    int peerCount, new;
    409452    uint8_t * peerCompact;
     
    412455        return;
    413456   
    414     tr_lockLock( &tor->lock );
     457    tr_torrentWriterLock( tor );
    415458    tr_trackerAnnouncePulse( tor->tracker, &peerCount, &peerCompact, 1 );
    416459    new = 0;
     
    418461    {
    419462        new = tr_torrentAddCompact( tor, TR_PEER_FROM_TRACKER,
    420                               peerCompact, peerCount );
     463                                    peerCompact, peerCount );
    421464        free( peerCompact );
    422465    }
    423466    tr_dbg( "got %i peers from manual announce, used %i", peerCount, new );
    424     tr_lockUnlock( &tor->lock );
     467    tr_torrentWriterUnlock( tor );
     468#endif
    425469}
    426470
     
    428472{
    429473    tr_stat_t * s;
    430     tr_peer_t * peer;
    431     tr_info_t * inf = &tor->info;
    432474    tr_tracker_t * tc;
    433475    int i;
    434476
     477    tr_torrentReaderLock( tor );
     478
    435479    tor->statCur = ( tor->statCur + 1 ) % 2;
    436480    s = &tor->stats[tor->statCur];
    437481
    438     if( ( tor->status & TR_STATUS_STOPPED ) ||
    439         ( ( tor->status & TR_STATUS_STOPPING ) &&
    440           tr_date() > tor->stopDate + 60000 ) )
    441     {
    442         torrentReallyStop( tor );
    443         tor->status = TR_STATUS_PAUSE;
    444     }
    445 
    446     tr_lockLock( &tor->lock );
    447 
    448     s->status = tor->status;
    449482    s->error  = tor->error;
    450483    memcpy( s->errorString, tor->errorString,
     
    453486    tc = tor->tracker;
    454487    s->cannotConnect = tr_trackerCannotConnect( tc );
    455     s->tracker = ( tc ? tr_trackerGet( tc ) : &inf->trackerList[0].list[0] );
    456 
     488    s->tracker = ( tc ? tr_trackerGet( tc ) : &tor->info.trackerList[0].list[0] );
     489
     490    /* peers... */
     491    memset( s->peersFrom, 0, sizeof( s->peersFrom ) );
    457492    s->peersTotal       = 0;
    458     memset( s->peersFrom, 0, sizeof( s->peersFrom ) );
    459493    s->peersUploading   = 0;
    460494    s->peersDownloading = 0;
    461    
    462     for( i = 0; i < tor->peerCount; i++ )
    463     {
    464         peer = tor->peers[i];
    465    
    466         if( tr_peerIsConnected( peer ) )
    467         {
    468             (s->peersTotal)++;
    469             (s->peersFrom[ tr_peerIsFrom( peer ) ])++;
     495    for( i=0; i<tor->peerCount; ++i ) {
     496        const tr_peer_t * peer = tor->peers[i];
     497        if( tr_peerIsConnected( peer ) ) {
     498            ++s->peersTotal;
     499            ++s->peersFrom[tr_peerIsFrom(peer)];
    470500            if( tr_peerAmInterested( peer ) && !tr_peerIsChoking( peer ) )
    471             {
    472                 (s->peersUploading)++;
    473             }
     501                ++s->peersUploading;
    474502            if( !tr_peerAmChoking( peer ) )
    475             {
    476                 (s->peersDownloading)++;
    477             }
     503                ++s->peersDownloading;
    478504        }
    479505    }
     
    481507    s->percentDone = tr_cpPercentDone( tor->completion );
    482508    s->percentComplete = tr_cpPercentComplete( tor->completion );
    483     s->cpStatus = tr_cpGetStatus( tor->completion );
    484509    s->left     = tr_cpLeftUntilDone( tor->completion );
    485     if( tor->status & TR_STATUS_DOWNLOAD )
    486     {
    487         s->rateDownload = tr_rcRate( tor->download );
    488     }
    489     else
    490     {
    491         /* tr_rcRate() doesn't make the difference between 'piece'
    492            messages and other messages, which causes a non-zero
    493            download rate even tough we are not downloading. So we
    494            force it to zero not to confuse the user. */
    495         s->rateDownload = 0.0;
    496     }
     510
     511
     512    if( tor->recheckFlag )
     513        s->status = TR_STATUS_CHECK_WAIT;
     514    else switch( tor->runStatus ) {
     515        case TR_RUN_STOPPING: s->status = TR_STATUS_STOPPING; break;
     516        case TR_RUN_STOPPED: s->status = TR_STATUS_STOPPED; break;
     517        case TR_RUN_CHECKING: s->status = TR_STATUS_CHECK; break;
     518        case TR_RUN_RUNNING: switch( tor->cpStatus ) {
     519            case TR_CP_INCOMPLETE: s->status = TR_STATUS_DOWNLOAD; break;
     520            case TR_CP_DONE: s->status = TR_STATUS_DONE; break;
     521            case TR_CP_COMPLETE: s->status = TR_STATUS_SEED; break;
     522        }
     523    }
     524
     525    s->cpStatus = tor->cpStatus;
     526
     527    /* tr_rcRate() doesn't make the difference between 'piece'
     528       messages and other messages, which causes a non-zero
     529       download rate even tough we are not downloading. So we
     530       force it to zero not to confuse the user. */
     531    s->rateDownload = tor->runStatus==TR_RUN_RUNNING
     532        ? tr_rcRate( tor->download )
     533        : 0.0;
    497534    s->rateUpload = tr_rcRate( tor->upload );
    498535   
     
    506543    s->activityDate = tor->activityDate;
    507544
    508     if( s->rateDownload < 0.1 )
    509     {
    510         s->eta = -1;
    511     }
    512     else
    513     {
    514         s->eta = (float) s->left / s->rateDownload / 1024.0;
    515     }
     545    s->eta = s->rateDownload < 0.1
     546        ? -1.0f
     547        : (s->left / s->rateDownload / 1024.0);
    516548
    517549    s->uploaded        = tor->uploadedCur   + tor->uploadedPrev;
    518550    s->downloaded      = tor->downloadedCur + tor->downloadedPrev;
    519551    s->downloadedValid = tr_cpDownloadedValid( tor->completion );
     552   
     553    s->ratio = s->downloaded || s->downloadedValid
     554      ? (float)s->uploaded / (float)MAX(s->downloaded, s->downloadedValid)
     555      : TR_RATIO_NA;
    520556   
    521     if( s->downloaded == 0 && s->percentDone == 0.0 )
    522     {
    523         s->ratio = TR_RATIO_NA;
    524     }
    525     else
    526     {
    527         s->ratio = (float)s->uploaded
    528                  / (float)MAX(s->downloaded, s->downloadedValid);
    529     }
    530    
    531     tr_lockUnlock( &tor->lock );
     557    tr_torrentReaderUnlock( tor );
    532558
    533559    return s;
    534560}
    535561
    536 tr_peer_stat_t * tr_torrentPeers( tr_torrent_t * tor, int * peerCount )
     562tr_peer_stat_t *
     563tr_torrentPeers( const tr_torrent_t * tor, int * peerCount )
    537564{
    538565    tr_peer_stat_t * peers;
    539566
    540     tr_lockLock( &tor->lock );
     567    tr_torrentReaderLock( tor );
    541568
    542569    *peerCount = tor->peerCount;
     
    577604    }
    578605   
    579     tr_lockUnlock( &tor->lock );
     606    tr_torrentReaderUnlock( tor );
    580607   
    581608    return peers;
     
    584611void tr_torrentPeersFree( tr_peer_stat_t * peers, int peerCount UNUSED )
    585612{
    586     if (peers == NULL)
    587         return;
    588 
    589     free( peers );
    590 }
    591 
    592 void tr_torrentAvailability( tr_torrent_t * tor, int8_t * tab, int size )
     613    tr_free( peers );
     614}
     615
     616void tr_torrentAvailability( const tr_torrent_t * tor, int8_t * tab, int size )
    593617{
    594618    int i, j, piece;
    595619    float interval;
    596620
    597     tr_lockLock( &tor->lock );
     621    tr_torrentReaderLock( tor );
     622
    598623    interval = (float)tor->info.pieceCount / (float)size;
    599624    for( i = 0; i < size; i++ )
     
    616641        }
    617642    }
    618     tr_lockUnlock( &tor->lock );
     643
     644    tr_torrentReaderUnlock( tor );
    619645}
    620646
     
    678704    int i;
    679705    float * f;
    680 
    681     tr_lockLock( &tor->lock );
     706    tr_torrentReaderLock( tor );
     707
    682708    f = calloc ( tor->info.fileCount, sizeof( float ) );
    683709    for( i=0; i<tor->info.fileCount; ++i )
    684710       f[i] = tr_torrentFileCompletion ( tor, i );
    685     tr_lockUnlock( &tor->lock );
    686 
     711
     712    tr_torrentReaderUnlock( tor );
    687713    return f;
    688714}
    689715
    690 void tr_torrentAmountFinished( tr_torrent_t * tor, float * tab, int size )
    691 {
    692     int i, piece;
     716void tr_torrentAmountFinished( const tr_torrent_t * tor, float * tab, int size )
     717{
     718    int i;
    693719    float interval;
    694 
    695     tr_lockLock( &tor->lock );
     720    tr_torrentReaderLock( tor );
     721
    696722    interval = (float)tor->info.pieceCount / (float)size;
    697723    for( i = 0; i < size; i++ )
    698724    {
    699         piece = i * interval;
     725        int piece = i * interval;
    700726        tab[i] = tr_cpPercentBlocksInPiece( tor->completion, piece );
    701727    }
    702     tr_lockUnlock( &tor->lock );
     728
     729    tr_torrentReaderUnlock( tor );
     730}
     731
     732void
     733tr_torrentResetTransferStats( tr_torrent_t * tor )
     734{
     735    tr_torrentWriterLock( tor );
     736
     737    tor->downloadedPrev += tor->downloadedCur;
     738    tor->downloadedCur   = 0;
     739    tor->uploadedPrev   += tor->uploadedCur;
     740    tor->uploadedCur     = 0;
     741
     742    tr_torrentWriterUnlock( tor );
     743}
     744
     745
     746void
     747tr_torrentSetHasPiece( tr_torrent_t * tor, int pieceIndex, int has )
     748{
     749    tr_torrentWriterLock( tor );
     750
     751    if( has )
     752        tr_cpPieceAdd( tor->completion, pieceIndex );
     753    else
     754        tr_cpPieceRem( tor->completion, pieceIndex );
     755
     756    tr_torrentWriterUnlock( tor );
    703757}
    704758
     
    708762}
    709763
    710 void tr_torrentRemoveFastResume( tr_torrent_t * tor )
    711 {
    712     tr_ioRemoveResume( tor );
    713 }
    714 
    715 /***********************************************************************
    716  * tr_torrentClose
    717  ***********************************************************************
    718  * Frees memory allocated by tr_torrentInit.
    719  **********************************************************************/
    720 void tr_torrentClose( tr_torrent_t * tor )
    721 {
    722     tr_handle_t * h = tor->handle;
    723     tr_info_t * inf = &tor->info;
    724 
    725     /* Join the thread first */
    726     torrentReallyStop( tor );
    727 
    728     tr_sharedLock( h->shared );
    729 
    730     h->torrentCount--;
    731 
    732     tr_lockClose( &tor->lock );
    733     tr_condClose( &tor->cond );
    734     tr_cpClose( tor->completion );
    735 
    736     tr_rcClose( tor->upload );
    737     tr_rcClose( tor->download );
    738     tr_rcClose( tor->swarmspeed );
    739 
    740     if( tor->destination )
    741     {
    742         free( tor->destination );
    743     }
    744 
    745     tr_metainfoFree( inf );
    746 
    747     if( tor->prev )
    748     {
    749         tor->prev->next = tor->next;
    750     }
    751     else
    752     {
    753         h->torrentList = tor->next;
    754     }
    755     if( tor->next )
    756     {
    757         tor->next->prev = tor->prev;
    758     }
    759     free( tor );
    760 
    761     tr_sharedUnlock( h->shared );
    762 }
     764void tr_torrentRecheck( tr_torrent_t * tor )
     765{
     766    tor->recheckFlag = TRUE;
     767}
     768
    763769
    764770int tr_torrentAttachPeer( tr_torrent_t * tor, tr_peer_t * peer )
     
    813819}
    814820
    815 /***********************************************************************
    816  * Push a torrent's call to tr_ioInit through a queue in a worker
    817  * thread so that only one torrent can be in checkFiles() at a time.
    818  **********************************************************************/
    819 
    820 struct tr_io_init_list_t
    821 {
    822     tr_torrent_t              * tor;
    823     struct tr_io_init_list_t  * next;
    824 };
    825 
    826 static struct tr_io_init_list_t * ioInitQueue = NULL;
    827 
    828 static int ioInitWorkerRunning = 0;
    829 
    830 static tr_thread_t ioInitThread;
    831 
    832 static tr_lock_t* getIOLock( tr_handle_t * h )
    833 {
    834     static tr_lock_t * lock = NULL;
     821/***
     822****
     823***/
     824
     825static void setRunState( tr_torrent_t * tor, run_status_t run )
     826{
     827    tr_torrentWriterLock( tor );
     828    tor->runStatus = run;
     829    tr_torrentWriterUnlock( tor );
     830}
     831
     832void tr_torrentStart( tr_torrent_t * tor )
     833{
     834    setRunState( tor, TR_RUN_RUNNING );
     835}
     836
     837void tr_torrentStop( tr_torrent_t * tor )
     838{
     839    setRunState( tor, TR_RUN_STOPPING );
     840}
     841
     842void tr_torrentClose( tr_torrent_t * tor )
     843{
     844    tr_torrentStop( tor );
     845    tor->dieFlag = TRUE;
     846}
     847
     848static void
     849tr_torrentFree( tr_torrent_t * tor )
     850{
     851    tr_torrent_t * t;
     852    tr_handle_t * h = tor->handle;
     853    tr_info_t * inf = &tor->info;
    835854
    836855    tr_sharedLock( h->shared );
    837     if( lock == NULL )
    838     {
    839         lock = calloc( 1, sizeof( tr_lock_t ) );
    840         tr_lockInit( lock );
    841     }
     856
     857    h->torrentCount--;
     858
     859    tr_rwClose( &tor->lock );
     860    tr_cpClose( tor->completion );
     861
     862    tr_rcClose( tor->upload );
     863    tr_rcClose( tor->download );
     864    tr_rcClose( tor->swarmspeed );
     865
     866    tr_free( tor->destination );
     867
     868    tr_metainfoFree( inf );
     869
     870    if( tor == h->torrentList )
     871        h->torrentList = tor->next;
     872    else for( t=h->torrentList; t!=NULL; t=t->next ) {
     873        if( t->next == tor ) {
     874            t->next = tor->next;
     875            break;
     876        }
     877    }
     878
     879    tr_free( tor );
     880
    842881    tr_sharedUnlock( h->shared );
    843 
    844     return lock;
    845 }
    846 
    847 static void ioInitWorker( void * user_data )
    848 {
    849     tr_handle_t * h = (tr_handle_t*) user_data;
    850 
    851     for (;;)
    852     {
    853         char name[32];
    854 
    855         /* find the next torrent to process */
    856         tr_torrent_t * tor = NULL;
    857         tr_lock_t * lock = getIOLock( h );
    858         tr_lockLock( lock );
    859         if( ioInitQueue != NULL )
     882}
     883
     884static void
     885torrentThreadLoop ( void * _tor )
     886{
     887    static tr_lock_t checkFilesLock;
     888    static int checkFilesLockInited = FALSE;
     889    tr_torrent_t * tor = _tor;
     890
     891    /* create the check-files mutex */
     892    if( !checkFilesLockInited ) {
     893        tr_lockInit( &checkFilesLock );
     894        checkFilesLockInited = TRUE;
     895    }
     896
     897    /* loop until the torrent is being deleted */
     898    while( ! ( tor->dieFlag && (tor->runStatus == TR_RUN_STOPPED) ) )
     899    {
     900        cp_status_t cpStatus;
     901
     902        /* sleep a little while */
     903        tr_wait( INTERVAL_MSEC );
     904
     905        /* if we're stopping... */
     906        if( tor->runStatus == TR_RUN_STOPPING )
    860907        {
    861             struct tr_io_init_list_t * node = ioInitQueue;
    862             ioInitQueue = node->next;
    863             tor = node->tor;
    864             free( node );
    865         }
    866         tr_lockUnlock( lock );
    867 
    868         /* if no torrents, this worker thread is done */
    869         if( tor == NULL )
     908            int i;
     909            int peerCount;
     910            uint8_t * peerCompact;
     911            tr_torrentWriterLock( tor );
     912
     913            /* close the IO */
     914            tr_ioClose( tor->io );
     915            tor->io = NULL;
     916
     917            /* close the tracker */
     918            tr_trackerStopped( tor->tracker );
     919            tr_trackerPulse( tor->tracker, &peerCount, &peerCompact );
     920            tr_trackerClose( tor->tracker );
     921            tor->tracker = NULL;
     922
     923            /* close the peers */
     924            for( i=0; i<tor->peerCount; ++i )
     925                tr_peerDestroy( tor->peers[i] );
     926            tor->peerCount = 0;
     927
     928            /* resest the transfer rates */
     929            tr_rcReset( tor->download );
     930            tr_rcReset( tor->upload );
     931            tr_rcReset( tor->swarmspeed );
     932
     933            tor->stopDate = tr_date();
     934            tor->runStatus = TR_RUN_STOPPED;
     935
     936            tr_torrentWriterUnlock( tor );
     937        }
     938
     939        /* do we need to check files? */
     940        if( tor->recheckFlag )
    870941        {
    871           break;
    872         }
    873 
    874         /* check this torrent's files */
    875         tor->status = TR_STATUS_CHECK;
    876        
    877         tr_dbg( "torrent %s checking files", tor->info.name );
    878         tr_lockLock( &tor->lock );
    879         tr_cpReset( tor->completion );
    880         tor->io = tr_ioInit( tor );
    881         tr_lockUnlock( &tor->lock );
    882 
    883         snprintf( name, sizeof( name ), "torrent %p", tor );
    884         tr_threadCreate( &tor->thread, downloadLoop, tor, name );
    885     }
    886 
    887     ioInitWorkerRunning = 0;
    888 }
    889 
    890 /* add tor to the queue of torrents waiting for an tr_ioInit */
    891 static void ioInitAdd( tr_torrent_t * tor )
    892 {
    893     tr_lock_t * lock = getIOLock( tor->handle );
    894     struct tr_io_init_list_t * node;
    895     tr_lockLock( lock );
    896 
    897     /* enqueue this torrent to have its io initialized */
    898     node = malloc( sizeof( struct tr_io_init_list_t ) );
    899     node->tor = tor;
    900     node->next = NULL;
    901     if( ioInitQueue == NULL )
    902     {
    903         ioInitQueue = node;
    904     }
    905     else
    906     {
    907         struct tr_io_init_list_t * l = ioInitQueue;
    908         while( l->next != NULL )
    909         {
    910             l = l->next;
    911         }
    912         l->next = node;
    913     }
    914 
    915     /* ensure there's a worker thread to process the queue */
    916     if( !ioInitWorkerRunning )
    917     {
    918         ioInitWorkerRunning = 1;
    919         tr_threadCreate( &ioInitThread, ioInitWorker, tor->handle, "ioInit" );
    920     }
    921    
    922     tr_lockUnlock( lock );
    923 }
    924 
    925 /* remove tor from the queue of torrents waiting for an tr_ioInit.
    926    return nonzero if tor was found and removed */
    927 static int ioInitRemove( tr_torrent_t * tor )
    928 {
    929     tr_lock_t * lock = getIOLock( tor->handle );
    930     struct tr_io_init_list_t *node, *prev;
    931     tr_lockLock( lock );
    932 
    933     /* find tor's node */
    934     for( prev = NULL, node = ioInitQueue;
    935          node != NULL && node->tor != tor;
    936          prev=node, node=node->next );
    937 
    938     if( node != NULL )
    939     {
    940         if( prev == NULL )
    941         {
    942             ioInitQueue = node->next;
    943         }
    944         else
    945         {
    946             prev->next = node->next;
    947         }
    948     }
    949 
    950     tr_lockUnlock( lock );
    951     return node != NULL;
    952 }
    953 
    954 /***********************************************************************
    955  * downloadLoop
    956  **********************************************************************/
    957 static void downloadLoop( void * _tor )
    958 {
    959     tr_torrent_t * tor = _tor;
    960     int            i, ret;
    961     int            peerCount, used;
    962     cp_status_t    cpState, cpPrevState;
    963     uint8_t      * peerCompact;
    964     tr_peer_t    * peer;
    965 
    966     tr_lockLock( &tor->lock );
    967 
    968     cpState = cpPrevState = tr_cpGetStatus( tor->completion );
    969     switch( cpState ) {
    970         case TR_CP_COMPLETE:   tor->status = TR_STATUS_SEED; break;
    971         case TR_CP_DONE:       tor->status = TR_STATUS_DONE; break;
    972         case TR_CP_INCOMPLETE: tor->status = TR_STATUS_DOWNLOAD; break;
    973     }
    974 
    975     while( !tor->die )
    976     {
    977         tr_lockUnlock( &tor->lock );
    978         tr_wait( INTERVAL_MSEC );
    979         tr_lockLock( &tor->lock );
    980 
    981         cpState = tr_cpGetStatus( tor->completion );
    982 
    983         if( cpState != cpPrevState )
    984         {
    985             switch( cpState ) {
    986                 case TR_CP_COMPLETE:   tor->status = TR_STATUS_SEED; break;
    987                 case TR_CP_DONE:       tor->status = TR_STATUS_DONE; break;
    988                 case TR_CP_INCOMPLETE: tor->status = TR_STATUS_DOWNLOAD; break;
    989             }
    990 
    991             tor->hasChangedState = cpState;
    992 
    993             if( cpState == TR_CP_COMPLETE )
    994                 tr_trackerCompleted( tor->tracker );
    995 
    996             tr_ioSync( tor->io );
    997 
    998             cpPrevState = cpState;
    999         }
    1000 
    1001         /* Try to get new peers or to send a message to the tracker */
    1002         tr_trackerPulse( tor->tracker, &peerCount, &peerCompact );
    1003         if( peerCount > 0 )
    1004         {
    1005             used = tr_torrentAddCompact( tor, TR_PEER_FROM_TRACKER,
    1006                                          peerCompact, peerCount );
    1007             free( peerCompact );
    1008             tr_dbg( "got %i peers from announce, used %i", peerCount, used );
    1009         }
    1010         if( tor->status & TR_STATUS_STOPPED )
    1011         {
    1012             break;
    1013         }
    1014 
    1015         /* Stopping: make sure all files are closed and stop talking
    1016            to peers */
    1017         if( tor->status & TR_STATUS_STOPPING )
    1018         {
    1019             if( tor->io )
     942            if( !tr_lockTryLock( &checkFilesLock ) )
    1020943            {
    1021                 tr_ioClose( tor->io ); tor->io = NULL;
    1022                 tr_condSignal( &tor->cond );
     944                run_status_t realStatus;
     945
     946                tr_torrentWriterLock( tor );
     947                realStatus = tor->runStatus;
     948                tor->recheckFlag = FALSE;
     949                tor->runStatus = TR_RUN_CHECKING;
     950                tr_torrentWriterUnlock( tor );
     951
     952                tr_ioCheckFiles( tor, TR_RECHECK_FORCE );
     953                setRunState( tor, realStatus );
     954
     955                tr_lockUnlock( &checkFilesLock );
    1023956            }
    1024957            continue;
    1025958        }
    1026959
    1027         /* Shuffle peers */
    1028         if( tor->peerCount > 1 )
     960        /* if we're paused or stopped, not much to do... */
     961        if( tor->runStatus == TR_RUN_STOPPED )
     962            continue;
     963
     964        /* ping our peers if we're running... */
     965        if( tor->runStatus == TR_RUN_RUNNING )
    1029966        {
    1030             peer = tor->peers[0];
    1031             memmove( &tor->peers[0], &tor->peers[1],
    1032                     ( tor->peerCount - 1 ) * sizeof( void * ) );
    1033             tor->peers[tor->peerCount - 1] = peer;
    1034         }
    1035 
    1036         /* Receive/send messages */
    1037         for( i = 0; i < tor->peerCount; )
    1038         {
    1039             peer = tor->peers[i];
    1040 
    1041             ret = tr_peerPulse( peer );
    1042             if( ret & TR_ERROR_IO_MASK )
    1043             {
    1044                 tr_err( "Fatal error, stopping download (%d)", ret );
    1045                 torrentStop( tor );
    1046                 tor->error = ret;
    1047                 snprintf( tor->errorString, sizeof( tor->errorString ),
    1048                           "%s", tr_errorString( ret ) );
    1049                 break;
     967            int i;
     968            int peerCount;
     969            uint8_t * peerCompact;
     970
     971            /* starting to run... */
     972            if( tor->io == NULL ) {
     973                tr_torrentResetTransferStats( tor );
     974                tor->io = tr_ioInitFast( tor );
     975                if( tor->io == NULL ) {
     976                    tor->recheckFlag = TRUE;
     977                    continue;
     978                }
     979                tor->tracker = tr_trackerInit( tor );
     980                tor->startDate = tr_date();
    1050981            }
    1051             if( ret )
    1052             {
    1053                 tr_peerDestroy( peer );
    1054                 tor->peerCount--;
    1055                 memmove( &tor->peers[i], &tor->peers[i+1],
    1056                          ( tor->peerCount - i ) * sizeof( void * ) );
    1057                 continue;
     982
     983            /* refresh our completion state */
     984            tr_torrentWriterLock( tor );
     985            cpStatus = tr_cpGetStatus( tor->completion );
     986            if( cpStatus != tor->cpStatus ) {
     987                tor->hasChangedState = tor->cpStatus = cpStatus;
     988                if( (cpStatus == TR_CP_COMPLETE) && tor->tracker!=NULL )
     989                    tr_trackerCompleted( tor->tracker );
     990                tr_ioSync( tor->io );
    1058991            }
    1059             i++;
    1060         }
    1061     }
    1062 
    1063     tr_lockUnlock( &tor->lock );
    1064 
    1065     if( tor->io )
    1066     {
    1067         tr_ioClose( tor->io ); tor->io = NULL;
    1068         tr_condSignal( &tor->cond );
    1069     }
    1070 
    1071     tor->status = TR_STATUS_STOPPED;
    1072 }
     992            tr_torrentWriterUnlock( tor );
     993
     994            /* ping the tracker... */
     995            tr_trackerPulse( tor->tracker, &peerCount, &peerCompact );
     996            if( peerCount > 0 ) {
     997                int used = tr_torrentAddCompact( tor, TR_PEER_FROM_TRACKER,
     998                                                 peerCompact, peerCount );
     999                tr_dbg( "got %i peers from announce, used %i", peerCount, used );
     1000                free( peerCompact );
     1001            }
     1002
     1003            /* Shuffle peers */
     1004            if ( tor->peerCount > 1 ) {
     1005                tr_peer_t * tmp = tor->peers[0];
     1006                memmove( tor->peers, tor->peers+1,
     1007                        (tor->peerCount-1) * sizeof(void*) );
     1008                tor->peers[tor->peerCount - 1] = tmp;
     1009            }
     1010
     1011            /* receive/send messages */
     1012            for( i=0; i<tor->peerCount; ) {
     1013                tr_peer_t * peer = tor->peers[i];
     1014                int ret = tr_peerPulse( peer );
     1015                if( ret & TR_ERROR_IO_MASK ) {
     1016                    tr_err( "Fatal error, stopping download (%d)", ret );
     1017                    tor->runStatus = TR_RUN_STOPPING;
     1018                    tor->error = ret;
     1019                    strlcpy( tor->errorString,
     1020                             tr_errorString(ret),
     1021                             sizeof(tor->errorString) );
     1022                    break;
     1023                }
     1024                if( ret ) {
     1025                    tr_peerDestroy( peer );
     1026                    tor->peerCount--;
     1027                    memmove( &tor->peers[i], &tor->peers[i+1],
     1028                             (tor->peerCount-i)*sizeof(void*) );
     1029                    continue;
     1030                }
     1031                i++;
     1032            }
     1033        }
     1034    }
     1035
     1036    tr_ioClose( tor->io );
     1037    tr_torrentFree( tor );
     1038}
     1039
    10731040
    10741041/***
     
    10781045***/
    10791046
    1080 static int
    1081 getBytePiece( const tr_info_t * info, uint64_t byteOffset )
    1082 {
    1083     assert( info != NULL );
    1084     assert( info->pieceSize != 0 );
    1085 
    1086     return byteOffset / info->pieceSize;
    1087 }
    1088 
    1089 static void
    1090 initFilePieces ( tr_info_t * info, int fileIndex )
    1091 {
    1092     tr_file_t * file = &info->files[fileIndex];
    1093     uint64_t firstByte, lastByte;
    1094 
    1095     assert( info != NULL );
    1096     assert( 0<=fileIndex && fileIndex<info->fileCount );
    1097 
    1098     file = &info->files[fileIndex];
    1099     firstByte = file->offset;
    1100     lastByte = firstByte + (file->length ? file->length-1 : 0);
    1101     file->firstPiece = getBytePiece( info, firstByte );
    1102     file->lastPiece = getBytePiece( info, lastByte );
    1103     tr_dbg( "file #%d is in pieces [%d...%d] (%s)", fileIndex, file->firstPiece, file->lastPiece, file->name );
    1104 }
    1105 
    1106 static tr_priority_t
    1107 calculatePiecePriority ( const tr_torrent_t * tor,
    1108                          int                  piece )
    1109 {
    1110     int i;
    1111     tr_priority_t priority = TR_PRI_DND;
    1112 
    1113     for( i=0; i<tor->info.fileCount; ++i )
    1114     {
    1115         const tr_file_t * file = &tor->info.files[i];
    1116         if ( file->firstPiece <= piece
    1117           && file->lastPiece  >= piece
    1118           && file->priority   >  priority)
    1119               priority = file->priority;
    1120     }
    1121 
    1122     return priority;
    1123 }
    1124 
    1125 void
    1126 tr_torrentInitFilePieces( tr_torrent_t * tor )
    1127 {
    1128     int i;
    1129     uint64_t offset = 0;
    1130 
    1131     assert( tor != NULL );
    1132 
    1133     for( i=0; i<tor->info.fileCount; ++i ) {
    1134       tor->info.files[i].offset = offset;
    1135       offset += tor->info.files[i].length;
    1136       initFilePieces( &tor->info, i );
    1137     }
    1138 
    1139     for( i=0; i<tor->info.pieceCount; ++i )
    1140       tor->info.pieces[i].priority = calculatePiecePriority( tor, i );
    1141 }
    1142 
    11431047void
    11441048tr_torrentSetFilePriority( tr_torrent_t   * tor,
     
    11481052    int i;
    11491053    tr_file_t * file;
     1054
     1055    tr_torrentWriterLock( tor );
    11501056
    11511057    assert( tor != NULL );
     
    11621068             fileIndex, file->firstPiece, file->lastPiece,
    11631069             priority, tor->info.files[fileIndex].name );
     1070
     1071    tr_torrentWriterUnlock( tor );
    11641072}
    11651073
     
    11671075tr_torrentGetFilePriority( const tr_torrent_t *  tor, int file )
    11681076{
     1077    tr_priority_t ret;
     1078
     1079    tr_torrentReaderLock( tor );
    11691080    assert( tor != NULL );
    11701081    assert( 0<=file && file<tor->info.fileCount );
    1171 
    1172     return tor->info.files[file].priority;
     1082    ret = tor->info.files[file].priority;
     1083    tr_torrentReaderUnlock( tor );
     1084
     1085    return ret;
    11731086}
    11741087
     
    11871100{
    11881101    int i;
    1189     tr_priority_t * p = malloc( tor->info.fileCount * sizeof(tr_priority_t) );
     1102    tr_priority_t * p;
     1103
     1104    tr_torrentReaderLock( tor );
     1105    p = tr_malloc( tor->info.fileCount * sizeof(tr_priority_t) );
    11901106    for( i=0; i<tor->info.fileCount; ++i )
    11911107        p[i] = tor->info.files[i].priority;
     1108    tr_torrentReaderUnlock( tor );
     1109
    11921110    return p;
    11931111}
  • trunk/libtransmission/tracker.c

    r2149 r2202  
    475475void tr_trackerStopped( tr_tracker_t * tc )
    476476{
     477    if( tc == NULL )
     478        return;
     479
    477480    /* If we are already sending a query at the moment, we need to
    478481       reconnect */
     
    491494    size_t          ii;
    492495    struct tclist * dead;
     496
     497    if( tc == NULL )
     498        return;
    493499
    494500    killHttp( &tc->http );
     
    523529    {
    524530        event = "&event=started";
    525        
    526         tor->downloadedPrev += tor->downloadedCur;
    527         tor->downloadedCur   = 0;
    528         tor->uploadedPrev   += tor->uploadedCur;
    529         tor->uploadedCur     = 0;
     531       
     532        tr_torrentResetTransferStats( tor );
    530533
    531534        if( shouldChangePort( tc ) )
     
    833836    if( tc->stopped )
    834837    {
    835         tor->status = TR_STATUS_STOPPED;
     838        tr_torrentStop( tor );
    836839        tc->stopped = 0;
    837840    }
  • trunk/libtransmission/transmission.c

    r2185 r2202  
    146146    for( tor = h->torrentList; tor; tor = tor->next )
    147147    {
    148         tr_lockLock( &tor->lock );
    149         if( tor->status & TR_STATUS_DOWNLOAD )
     148        tr_torrentReaderLock( tor );
     149        if( tor->cpStatus == TR_CP_INCOMPLETE )
    150150            *dl += tr_rcRate( tor->download );
    151151        *ul += tr_rcRate( tor->upload );
    152         tr_lockUnlock( &tor->lock );
     152        tr_torrentReaderUnlock( tor );
    153153    }
    154154    tr_sharedUnlock( h->shared );
  • trunk/libtransmission/transmission.h

    r2154 r2202  
    214214typedef int8_t tr_priority_t;
    215215
    216 void tr_torrentInitFilePieces( tr_torrent_t * tor );
    217 
    218216/* priorities should be an array of tor->info.fileCount bytes,
    219217 * each holding a value of TR_PRI_NORMAL, _HIGH, _LOW, or _DND. */
     
    266264#define TR_EDUPLICATE   3
    267265#define TR_EOTHER       666
    268 tr_torrent_t * tr_torrentInit( tr_handle_t *, const char * path,
     266tr_torrent_t * tr_torrentInit( tr_handle_t *,
     267                               const char * path,
     268                               const char * destination,
    269269                               uint8_t * hash, int flags, int * error );
    270270
     
    275275 * instead of the filename.
    276276 **********************************************************************/
    277 tr_torrent_t * tr_torrentInitData( tr_handle_t *, uint8_t * data,
    278                                    size_t size, uint8_t * hash,
    279                                    int flags, int * error );
     277tr_torrent_t * tr_torrentInitData( tr_handle_t *,
     278                                   uint8_t * data, size_t size,
     279                                   const char * destination,
     280                                   uint8_t * hash, int flags, int * error );
    280281
    281282/***********************************************************************
     
    286287 * are currently no valid flags for this function.
    287288 **********************************************************************/
    288 tr_torrent_t * tr_torrentInitSaved( tr_handle_t *, const char * hashStr,
     289tr_torrent_t * tr_torrentInitSaved( tr_handle_t *,
     290                                    const char * hashStr,
     291                                    const char * destination,
    289292                                    int flags, int * error );
    290293
     
    318321
    319322void   tr_torrentSetFolder( tr_torrent_t *, const char * );
    320 char * tr_torrentGetFolder( tr_torrent_t * );
    321 
    322 int tr_torrentDuplicateDownload( tr_torrent_t * tor );
     323const char * tr_torrentGetFolder( const tr_torrent_t * );
    323324
    324325/***********************************************************************
     
    378379 ***********************************************************************/
    379380typedef struct tr_peer_stat_s tr_peer_stat_t;
    380 tr_peer_stat_t * tr_torrentPeers( tr_torrent_t *, int * peerCount );
     381tr_peer_stat_t * tr_torrentPeers( const tr_torrent_t *, int * peerCount );
    381382void tr_torrentPeersFree( tr_peer_stat_t *, int peerCount );
    382383
     
    389390 * of connected peers who have the piece.
    390391 **********************************************************************/
    391 void tr_torrentAvailability( tr_torrent_t *, int8_t * tab, int size );
    392 
    393 void tr_torrentAmountFinished( tr_torrent_t * tor, float * tab, int size );
     392void tr_torrentAvailability( const tr_torrent_t *, int8_t * tab, int size );
     393
     394void tr_torrentAmountFinished( const tr_torrent_t * tor, float * tab, int size );
    394395
    395396/***********************************************************************
     
    415416void tr_torrentRemoveSaved( tr_torrent_t * );
    416417
    417 void tr_torrentRemoveFastResume( tr_torrent_t * tor );
     418void tr_torrentRecheck( tr_torrent_t * );
    418419
    419420/***********************************************************************
     
    421422 ***********************************************************************
    422423 * Frees memory allocated by tr_torrentInit. If the torrent was running,
    423  * you must call tr_torrentStop() before closing it.
     424 * it is stopped first.
    424425 **********************************************************************/
    425426void tr_torrentClose( tr_torrent_t * );
     
    460461#define TR_FLAG_SAVE    0x01 /* save a copy of the torrent file */
    461462#define TR_FLAG_PRIVATE 0x02 /* do not share information for this torrent */
     463#define TR_FLAG_PAUSED  0x04 /* don't start the torrent when adding it */
    462464    int                  flags;
    463465
     
    489491typedef enum
    490492{
    491    TR_CP_COMPLETE,     /* has every piece */
    492    TR_CP_DONE,         /* has all the pieces but the DND ones */
    493    TR_CP_INCOMPLETE    /* doesn't have all the desired pieces */
     493    TR_CP_INCOMPLETE,   /* doesn't have all the desired pieces */
     494    TR_CP_DONE,         /* has all the pieces but the DND ones */
     495    TR_CP_COMPLETE      /* has every piece */
    494496}
    495497cp_status_t;
    496498
     499typedef enum
     500{
     501    TR_STATUS_CHECK_WAIT   = (1<<0), /* Waiting in queue to check files */
     502    TR_STATUS_CHECK        = (1<<1), /* Checking files */
     503    TR_STATUS_DOWNLOAD     = (1<<2), /* Downloading */
     504    TR_STATUS_DONE         = (1<<3), /* not at 100% so can't tell the tracker
     505                                        we're a seeder, but due to DND files
     506                                        there's nothing we want right now */
     507    TR_STATUS_SEED         = (1<<4), /* Seeding */
     508    TR_STATUS_STOPPING     = (1<<5), /* Sending 'stopped' to the tracker */
     509    TR_STATUS_STOPPED      = (1<<6)  /* Sent 'stopped' but thread still
     510                                        running (for internal use only) */
     511}
     512torrent_status_t;
     513
     514#define TR_STATUS_ACTIVE \
     515    (TR_STATUS_CHECK_WAIT|TR_STATUS_CHECK|TR_STATUS_DOWNLOAD|TR_STATUS_DONE|TR_STATUS_SEED)
     516#define TR_STATUS_INACTIVE \
     517    (TR_STATUS_STOPPING|TR_STATUS_STOPPED)
     518
    497519/***********************************************************************
    498520 * tr_stat_s
     
    500522struct tr_stat_s
    501523{
    502 #define TR_STATUS_CHECK_WAIT (1<<0) /* Waiting in queue to check files */
    503 #define TR_STATUS_CHECK      (1<<1) /* Checking files */
    504 #define TR_STATUS_DOWNLOAD   (1<<2) /* Downloading */
    505 #define TR_STATUS_DONE       (1<<3) /* not at 100% so can't tell the tracker
    506                                        we're a seeder, but due to DND files
    507                                        there's nothing we want right now */
    508 #define TR_STATUS_SEED       (1<<4) /* Seeding */
    509 #define TR_STATUS_STOPPING   (1<<5) /* Sending 'stopped' to the tracker */
    510 #define TR_STATUS_STOPPED    (1<<6) /* Sent 'stopped' but thread still
    511                                        running (for internal use only) */
    512 #define TR_STATUS_PAUSE      (1<<7) /* Paused */
    513 
    514 #define TR_STATUS_ACTIVE   (TR_STATUS_CHECK_WAIT|TR_STATUS_CHECK|TR_STATUS_DOWNLOAD|TR_STATUS_DONE|TR_STATUS_SEED)
    515 #define TR_STATUS_INACTIVE (TR_STATUS_STOPPING|TR_STATUS_STOPPED|TR_STATUS_PAUSE)
    516     int                 status;
     524    torrent_status_t    status;
    517525    cp_status_t         cpStatus;
    518526
Note: See TracChangeset for help on using the changeset viewer.