Ignore:
Timestamp:
Jan 14, 2007, 12:00:21 PM (15 years ago)
Author:
titer
Message:

Merge io branch into trunk

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/fdlimit.c

    r261 r1356  
    3131typedef struct tr_openFile_s
    3232{
    33     char       path[MAX_PATH_LENGTH];
     33    char       folder[MAX_PATH_LENGTH];
     34    char       name[MAX_PATH_LENGTH];
    3435    int        file;
     36    int        write;
    3537
    3638#define STATUS_INVALID 1
     
    4749{
    4850    tr_lock_t       lock;
     51    tr_cond_t       cond;
    4952   
    5053    int             reserved;
     
    5760
    5861/***********************************************************************
     62 * Local prototypes
     63 **********************************************************************/
     64static int  ErrorFromErrno();
     65static int  OpenFile( tr_fd_t * f, int i, char * folder, char * name,
     66                      int write );
     67static void CloseFile( tr_fd_t * f, int i );
     68
     69
     70/***********************************************************************
    5971 * tr_fdInit
    6072 **********************************************************************/
     
    6678    f = calloc( sizeof( tr_fd_t ), 1 );
    6779
    68     /* Init lock */
     80    /* Init lock and cond */
    6981    tr_lockInit( &f->lock );
     82    tr_condInit( &f->cond );
    7083
    7184    /* Detect the maximum number of open files or sockets */
     
    102115 * tr_fdFileOpen
    103116 **********************************************************************/
    104 int tr_fdFileOpen( tr_fd_t * f, char * path )
    105 {
    106     int i, winner;
     117int tr_fdFileOpen( tr_fd_t * f, char * folder, char * name, int write )
     118{
     119    int i, winner, ret;
    107120    uint64_t date;
    108121
     
    112125    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
    113126    {
    114         if( f->open[i].status > STATUS_INVALID &&
    115             !strcmp( path, f->open[i].path ) )
    116         {
    117             if( f->open[i].status & STATUS_CLOSING )
    118             {
    119                 /* Wait until the file is closed */
    120                 tr_lockUnlock( &f->lock );
    121                 tr_wait( 10 );
    122                 tr_lockLock( &f->lock );
    123                 i = -1;
    124                 continue;
    125             }
    126             winner = i;
    127             goto done;
    128         }
     127        if( f->open[i].status & STATUS_INVALID ||
     128            strcmp( folder, f->open[i].folder ) ||
     129            strcmp( name, f->open[i].name ) )
     130        {
     131            continue;
     132        }
     133        if( f->open[i].status & STATUS_CLOSING )
     134        {
     135            /* File is being closed by another thread, wait until
     136             * it's done before we reopen it */
     137            tr_condWait( &f->cond, &f->lock );
     138            i = -1;
     139            continue;
     140        }
     141        if( f->open[i].write < write )
     142        {
     143            /* File is open read-only and needs to be closed then
     144             * re-opened read-write */
     145            CloseFile( f, i );
     146            continue;
     147        }
     148        winner = i;
     149        goto done;
    129150    }
    130151
     
    139160    }
    140161
     162    /* All slots taken - close the oldest currently unused file */
    141163    for( ;; )
    142164    {
    143         /* Close the oldest currently unused file */
    144165        date   = tr_date() + 1;
    145166        winner = -1;
     
    160181        if( winner >= 0 )
    161182        {
    162             /* Close the file: we mark it as closing then release the
    163                lock while doing so, because close may take same time
    164                and we don't want to block other threads */
    165             tr_dbg( "Closing %s", f->open[winner].path );
    166             f->open[winner].status = STATUS_CLOSING;
    167             tr_lockUnlock( &f->lock );
    168             close( f->open[winner].file );
    169             tr_lockLock( &f->lock );
     183            CloseFile( f, winner );
    170184            goto open;
    171185        }
    172186
    173187        /* All used! Wait a bit and try again */
     188        tr_condWait( &f->cond, &f->lock );
     189    }
     190
     191open:
     192    if( ( ret = OpenFile( f, winner, folder, name, write ) ) )
     193    {
    174194        tr_lockUnlock( &f->lock );
    175         tr_wait( 10 );
    176         tr_lockLock( &f->lock );
    177     }
    178 
    179 open:
    180     tr_dbg( "Opening %s", path );
    181     snprintf( f->open[winner].path, MAX_PATH_LENGTH, "%s", path );
    182     f->open[winner].file = open( path, O_RDWR, 0 );
     195        return ret;
     196    }
     197    snprintf( f->open[winner].folder, MAX_PATH_LENGTH, "%s", folder );
     198    snprintf( f->open[winner].name, MAX_PATH_LENGTH, "%s", name );
     199    f->open[winner].write = write;
    183200
    184201done:
     
    207224    }
    208225   
     226    tr_condSignal( &f->cond );
    209227    tr_lockUnlock( &f->lock );
    210228}
     
    213231 * tr_fdFileClose
    214232 **********************************************************************/
    215 void tr_fdFileClose( tr_fd_t * f, char * path )
     233void tr_fdFileClose( tr_fd_t * f, char * folder, char * name )
    216234{
    217235    int i;
     
    219237    tr_lockLock( &f->lock );
    220238
    221     /* Is it already open? */
    222239    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
    223240    {
     
    226243            continue;
    227244        }
    228         if( !strcmp( path, f->open[i].path ) )
    229         {
    230             tr_dbg( "Closing %s", path );
    231             close( f->open[i].file );
    232             f->open[i].status = STATUS_INVALID;
    233             break;
    234         }
    235     }
    236 
    237     tr_lockUnlock( &f->lock );
    238 }
    239 
     245        if( !strcmp( folder, f->open[i].folder ) &&
     246            !strcmp( name, f->open[i].name ) )
     247        {
     248            CloseFile( f, i );
     249        }
     250    }
     251
     252    tr_lockUnlock( &f->lock );
     253}
     254
     255/***********************************************************************
     256 * tr_fdSocketWillCreate
     257 **********************************************************************/
    240258int tr_fdSocketWillCreate( tr_fd_t * f, int reserved )
    241259{
     
    274292}
    275293
     294/***********************************************************************
     295 * tr_fdSocketClosed
     296 **********************************************************************/
    276297void tr_fdSocketClosed( tr_fd_t * f, int reserved )
    277298{
     
    290311}
    291312
     313/***********************************************************************
     314 * tr_fdClose
     315 **********************************************************************/
    292316void tr_fdClose( tr_fd_t * f )
    293317{
    294318    tr_lockClose( &f->lock );
     319    tr_condClose( &f->cond );
    295320    free( f );
    296321}
    297322
     323
     324/***********************************************************************
     325 * Local functions
     326 **********************************************************************/
     327
     328/***********************************************************************
     329 * ErrorFromErrno
     330 **********************************************************************/
     331static int ErrorFromErrno()
     332{
     333    if( errno == EACCES || errno == EROFS )
     334        return TR_ERROR_IO_PERMISSIONS;
     335    return TR_ERROR_IO_OTHER;
     336}
     337
     338/***********************************************************************
     339 * CheckFolder
     340 ***********************************************************************
     341 *
     342 **********************************************************************/
     343static int OpenFile( tr_fd_t * f, int i, char * folder, char * name,
     344                     int write )
     345{
     346    tr_openFile_t * file = &f->open[i];
     347    struct stat sb;
     348    char * path;
     349
     350    tr_dbg( "Opening %s in %s (%d)", name, folder, write );
     351
     352    /* Make sure the parent folder exists */
     353    if( stat( folder, &sb ) || !S_ISDIR( sb.st_mode ) )
     354    {
     355        return TR_ERROR_IO_PARENT;
     356    }
     357
     358    asprintf( &path, "%s/%s", folder, name );
     359
     360    /* Create subfolders, if any */
     361    if( write )
     362    {
     363        char * p = path + strlen( folder ) + 1;
     364        char * s;
     365
     366        while( ( s = strchr( p, '/' ) ) )
     367        {
     368            *s = '\0';
     369            if( stat( path, &sb ) )
     370            {
     371                if( mkdir( path, 0777 ) )
     372                {
     373                    free( path );
     374                    return ErrorFromErrno();
     375                }
     376            }
     377            else
     378            {
     379                if( !S_ISDIR( sb.st_mode ) )
     380                {
     381                    free( path );
     382                    return TR_ERROR_IO_OTHER;
     383                }
     384            }
     385            *s = '/';
     386            p = s + 1;
     387        }
     388    }
     389
     390    /* Now try to really open the file */
     391    file->file = open( path, write ? ( O_RDWR | O_CREAT ) : O_RDONLY, 0666 );
     392    free( path );
     393
     394    if( file->file < 0 )
     395    {
     396        int ret = ErrorFromErrno();
     397        tr_err( "Could not open %s in %s (%d, %d)", name, folder, write, ret );
     398        return ret;
     399    }
     400
     401    return TR_OK;
     402}
     403
     404/***********************************************************************
     405 * CloseFile
     406 ***********************************************************************
     407 * We first mark it as closing then release the lock while doing so,
     408 * because close() may take same time and we don't want to block other
     409 * threads.
     410 **********************************************************************/
     411static void CloseFile( tr_fd_t * f, int i )
     412{
     413    tr_openFile_t * file = &f->open[i];
     414
     415    /* If it's already being closed by another thread, just wait till
     416     * it is done */
     417    while( file->status & STATUS_CLOSING )
     418    {
     419        tr_condWait( &f->cond, &f->lock );
     420    }
     421    if( file->status & STATUS_INVALID )
     422    {
     423        return;
     424    }
     425
     426    /* Nobody is closing it already, so let's do it */
     427    if( file->status & STATUS_USED )
     428    {
     429        tr_err( "CloseFile: closing a file that's being used!" );
     430    }
     431    tr_dbg( "Closing %s in %s (%d)", file->name, file->folder, file->write );
     432    file->status = STATUS_CLOSING;
     433    tr_lockUnlock( &f->lock );
     434    close( file->file );
     435    tr_lockLock( &f->lock );
     436    file->status = STATUS_INVALID;
     437    tr_condSignal( &f->cond );
     438}
     439
Note: See TracChangeset for help on using the changeset viewer.