~ubuntu-branches/ubuntu/hardy/transmission/hardy-updates

« back to all changes in this revision

Viewing changes to libtransmission/fdlimit.c

  • Committer: Bazaar Package Importer
  • Author(s): Philipp Benner
  • Date: 2007-12-05 14:37:05 UTC
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20071205143705-env7ahsls1gyb2eo
Tags: upstream-0.95.dfsg
ImportĀ upstreamĀ versionĀ 0.95.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/******************************************************************************
2
 
 * $Id: fdlimit.c 3811 2007-11-12 15:22:20Z charles $
 
2
 * $Id: fdlimit.c 4047 2007-12-03 16:53:24Z charles $
3
3
 *
4
4
 * Copyright (c) 2005-2006 Transmission authors and contributors
5
5
 *
35
35
#include <libgen.h> /* basename, dirname */
36
36
#include <fcntl.h> /* O_LARGEFILE */
37
37
 
38
 
#include <sys/queue.h> /* libevent needs this */
39
 
#include <sys/types.h> /* libevent needs this */
40
38
#include <event.h>
41
 
#include <evhttp.h>
42
39
#include <evutil.h>
43
40
 
44
41
#include "transmission.h"
89
86
 
90
87
enum
91
88
{
92
 
    TR_MAX_SOCKETS = 512,
93
 
 
94
 
    TR_MAX_OPEN_FILES = 16, /* real files, not sockets */
95
 
 
96
 
    TR_RESERVED_FDS   = 16 /* sockets reserved for tracker connections */
 
89
    TR_MAX_SOCKETS = 320,
 
90
 
 
91
    TR_MAX_OPEN_FILES = 8, /* real files, not sockets */
 
92
 
 
93
    TR_RESERVED_FDS = 16 /* sockets reserved for tracker connections */
97
94
};
98
95
 
99
96
struct tr_openfile
100
97
{
101
98
    unsigned int  isCheckedOut : 1;
102
99
    unsigned int  isWritable : 1;
 
100
    unsigned int  closeWhenDone : 1;
103
101
    char          filename[MAX_PATH_LENGTH];
104
102
    int           fd;
105
103
    uint64_t      date;
111
109
    int                  normal;
112
110
    int                  normalMax;
113
111
    tr_lock            * lock;
114
 
    tr_cond            * cond;
115
112
    struct tr_openfile   open[TR_MAX_OPEN_FILES];
116
113
};
117
114
 
134
131
    /* create subfolders, if any */
135
132
    if( write ) {
136
133
        char * tmp = tr_strdup( filename );
137
 
        const int val = tr_mkdirp( dirname(tmp), 0700 );
 
134
        const int val = tr_mkdirp( dirname(tmp), 0777 );
138
135
        tr_free( tmp );
139
136
        if( val )
140
137
            return tr_ioErrorFromErrno( );
149
146
    flags |= O_BINARY;
150
147
#endif
151
148
    errno = 0;
152
 
    file->fd = open( filename, flags, 0600 );
 
149
    file->fd = open( filename, flags, 0666 );
153
150
    if( file->fd < 0 ) {
154
151
        if( errno ) {
155
152
            tr_err( "Couldn't open '%s': %s", filename, strerror(errno) );
182
179
    close( o->fd );
183
180
    o->fd = -1;
184
181
    o->isCheckedOut = 0;
185
 
    tr_condSignal( gFd->cond );
186
182
}
187
183
 
188
184
static int
192
188
}
193
189
 
194
190
int
195
 
tr_fdFileOpen( const char * filename, int write )
 
191
tr_fdFileCheckout( const char * filename, int write )
196
192
{
197
 
    int i, winner;
 
193
    int i, winner = -1;
198
194
    struct tr_openfile * o;
199
195
 
200
196
    assert( filename && *filename );
217
213
 
218
214
        if( fileIsCheckedOut( o ) ) {
219
215
            dbgmsg( "found it!  it's open, but checked out.  waiting..." );
220
 
            tr_condWait( gFd->cond, gFd->lock );
 
216
            tr_lockUnlock( gFd->lock );
 
217
            tr_wait( 200 );
 
218
            tr_lockLock( gFd->lock );
221
219
            i = -1; /* reloop */
222
220
            continue;
223
221
        }
230
228
 
231
229
        dbgmsg( "found it!  it's ready for use!" );
232
230
        winner = i;
233
 
        goto done;
 
231
        break;
234
232
    }
235
233
 
236
 
 
237
234
    dbgmsg( "it's not already open.  looking for an open slot or an old file." );
238
 
    for( ;; )
 
235
    while( winner < 0 )
239
236
    {
240
237
        uint64_t date = tr_date( ) + 1;
241
 
        winner = -1;
242
238
 
 
239
        /* look for the file that's been open longest */
243
240
        for( i=0; i<TR_MAX_OPEN_FILES; ++i )
244
241
        {
245
242
            o = &gFd->open[i];
247
244
            if( !fileIsOpen( o ) ) {
248
245
                winner = i;
249
246
                dbgmsg( "found an empty slot in %d", winner );
250
 
                goto done;
 
247
                break;
251
248
            }
252
249
 
253
250
            if( date > o->date ) {
257
254
        }
258
255
 
259
256
        if( winner >= 0 ) {
260
 
            dbgmsg( "closing file '%s', slot #%d", gFd->open[winner].filename, winner );
261
 
            TrCloseFile( winner );
262
 
            goto done;
 
257
            if( fileIsOpen( &gFd->open[i] ) ) {
 
258
                dbgmsg( "closing file '%s', slot #%d", gFd->open[winner].filename, winner );
 
259
                TrCloseFile( winner );
 
260
            }
 
261
        } else { 
 
262
            dbgmsg( "everything's full!  waiting for someone else to finish something" );
 
263
            tr_lockUnlock( gFd->lock );
 
264
            tr_wait( 200 );
 
265
            tr_lockLock( gFd->lock );
263
266
        }
264
 
 
265
 
        /* All used! Wait a bit and try again */
266
 
        dbgmsg( "everything's full!  waiting for someone else to finish something" );
267
 
        tr_condWait( gFd->cond, gFd->lock );
268
267
    }
269
268
 
270
 
done:
271
 
 
 
269
    assert( winner >= 0 );
272
270
    o = &gFd->open[winner];
273
271
    if( !fileIsOpen( o ) )
274
272
    {
285
283
 
286
284
    dbgmsg( "checking out '%s' in slot %d", filename, winner );
287
285
    o->isCheckedOut = 1;
 
286
    o->closeWhenDone = 0;
288
287
    o->date = tr_date( );
289
288
    tr_lockUnlock( gFd->lock );
290
289
    return o->fd;
291
290
}
292
291
 
293
292
void
294
 
tr_fdFileRelease( int file )
295
 
{
296
 
    int i;
297
 
    tr_lockLock( gFd->lock );
298
 
 
299
 
    for( i=0; i<TR_MAX_OPEN_FILES; ++i ) {
300
 
        struct tr_openfile * o = &gFd->open[i];
301
 
        if( o->fd == file ) {
302
 
            dbgmsg( "releasing file '%s' in slot #%d", o->filename, i );
303
 
            /* fsync( o->fd ); */
304
 
            o->isCheckedOut = 0;
305
 
            break;
 
293
tr_fdFileReturn( int fd )
 
294
{
 
295
    int i;
 
296
    tr_lockLock( gFd->lock );
 
297
 
 
298
    for( i=0; i<TR_MAX_OPEN_FILES; ++i )
 
299
    {
 
300
        struct tr_openfile * o = &gFd->open[i];
 
301
        if( o->fd != fd )
 
302
            continue;
 
303
 
 
304
        dbgmsg( "releasing file '%s' in slot #%d", o->filename, i );
 
305
        o->isCheckedOut = 0;
 
306
        if( o->closeWhenDone )
 
307
            TrCloseFile( i );
 
308
        
 
309
        break;
 
310
    }
 
311
    
 
312
    tr_lockUnlock( gFd->lock );
 
313
}
 
314
 
 
315
void
 
316
tr_fdFileClose( const char * filename )
 
317
{
 
318
    int i;
 
319
    tr_lockLock( gFd->lock );
 
320
    dbgmsg( "tr_fdFileClose closing '%s'", filename );
 
321
 
 
322
    for( i=0; i<TR_MAX_OPEN_FILES; ++i )
 
323
    {
 
324
        struct tr_openfile * o = &gFd->open[i];
 
325
        if( !fileIsOpen(o) || strcmp(filename,o->filename) )
 
326
            continue;
 
327
 
 
328
        if( !o->isCheckedOut ) {
 
329
            dbgmsg( "not checked out, so closing it now... '%s'", filename );
 
330
            TrCloseFile( i );
 
331
        } else {
 
332
            dbgmsg( "flagging file '%s', slot #%d to be closed when checked in", gFd->open[i].filename, i );
 
333
            o->closeWhenDone = 1;
306
334
        }
307
335
    }
308
336
    
309
 
    tr_condSignal( gFd->cond );
310
337
    tr_lockUnlock( gFd->lock );
311
338
}
312
339
 
433
460
 
434
461
    gFd = tr_new0( struct tr_fd_s, 1 );
435
462
    gFd->lock = tr_lockNew( );
436
 
    gFd->cond = tr_condNew( );
437
463
 
438
464
    /* count the max number of sockets we can use */
439
465
    for( i=0; i<TR_MAX_SOCKETS; ++i )
461
487
            TrCloseFile( i );
462
488
 
463
489
    tr_lockFree( gFd->lock );
464
 
    tr_condFree( gFd->cond );
465
490
 
466
491
    tr_list_free( &reservedSockets, NULL );
467
492
    tr_free( gFd );