source: trunk/libtransmission/fdlimit.c @ 1125

Last change on this file since 1125 was 261, checked in by titer, 16 years ago

Updated svn:keywords

  • Property svn:keywords set to Date Rev Author Id
File size: 7.2 KB
Line 
1/******************************************************************************
2 * $Id: fdlimit.c 261 2006-05-29 21:27:31Z livings124 $
3 *
4 * Copyright (c) 2005-2006 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include "transmission.h"
26
27#define TR_MAX_OPEN_FILES 16 /* That is, real files, not sockets */
28#define TR_RESERVED_FDS   16 /* Number of sockets reserved for
29                                connections to trackers */
30
31typedef struct tr_openFile_s
32{
33    char       path[MAX_PATH_LENGTH];
34    int        file;
35
36#define STATUS_INVALID 1
37#define STATUS_UNUSED  2
38#define STATUS_USED    4
39#define STATUS_CLOSING 8
40    int        status;
41
42    uint64_t   date;
43
44} tr_openFile_t;
45
46struct tr_fd_s
47{
48    tr_lock_t       lock;
49   
50    int             reserved;
51
52    int             normal;
53    int             normalMax;
54
55    tr_openFile_t   open[TR_MAX_OPEN_FILES];
56};
57
58/***********************************************************************
59 * tr_fdInit
60 **********************************************************************/
61tr_fd_t * tr_fdInit()
62{
63    tr_fd_t * f;
64    int i, j, s[4096];
65
66    f = calloc( sizeof( tr_fd_t ), 1 );
67
68    /* Init lock */
69    tr_lockInit( &f->lock );
70
71    /* Detect the maximum number of open files or sockets */
72    for( i = 0; i < 4096; i++ )
73    {
74        if( ( s[i] = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
75        {
76            break;
77        }
78    }
79    for( j = 0; j < i; j++ )
80    {
81        tr_netClose( s[j] );
82    }
83
84    tr_dbg( "%d usable file descriptors", i );
85
86    f->reserved  = 0;
87    f->normal    = 0;
88
89    f->normalMax = i - TR_RESERVED_FDS - 10;
90        /* To be safe, in case the UI needs to write a preferences file
91           or something */
92
93    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
94    {
95        f->open[i].status = STATUS_INVALID;
96    }
97
98    return f;
99}
100
101/***********************************************************************
102 * tr_fdFileOpen
103 **********************************************************************/
104int tr_fdFileOpen( tr_fd_t * f, char * path )
105{
106    int i, winner;
107    uint64_t date;
108
109    tr_lockLock( &f->lock );
110
111    /* Is it already open? */
112    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
113    {
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        }
129    }
130
131    /* Can we open one more file? */
132    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
133    {
134        if( f->open[i].status & STATUS_INVALID )
135        {
136            winner = i;
137            goto open;
138        }
139    }
140
141    for( ;; )
142    {
143        /* Close the oldest currently unused file */
144        date   = tr_date() + 1;
145        winner = -1;
146
147        for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
148        {
149            if( !( f->open[i].status & STATUS_UNUSED ) )
150            {
151                continue;
152            }
153            if( f->open[i].date < date )
154            {
155                winner = i;
156                date   = f->open[i].date;
157            }
158        }
159
160        if( winner >= 0 )
161        {
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 );
170            goto open;
171        }
172
173        /* All used! Wait a bit and try again */
174        tr_lockUnlock( &f->lock );
175        tr_wait( 10 );
176        tr_lockLock( &f->lock );
177    }
178
179open:
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 );
183
184done:
185    f->open[winner].status = STATUS_USED;
186    f->open[winner].date   = tr_date();
187    tr_lockUnlock( &f->lock );
188   
189    return f->open[winner].file;
190}
191
192/***********************************************************************
193 * tr_fdFileRelease
194 **********************************************************************/
195void tr_fdFileRelease( tr_fd_t * f, int file )
196{
197    int i;
198    tr_lockLock( &f->lock );
199
200    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
201    {
202        if( f->open[i].file == file )
203        {
204            f->open[i].status = STATUS_UNUSED;
205            break;
206        }
207    }
208   
209    tr_lockUnlock( &f->lock );
210}
211
212/***********************************************************************
213 * tr_fdFileClose
214 **********************************************************************/
215void tr_fdFileClose( tr_fd_t * f, char * path )
216{
217    int i;
218
219    tr_lockLock( &f->lock );
220
221    /* Is it already open? */
222    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
223    {
224        if( f->open[i].status & STATUS_INVALID )
225        {
226            continue;
227        }
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
240int tr_fdSocketWillCreate( tr_fd_t * f, int reserved )
241{
242    int ret;
243
244    tr_lockLock( &f->lock );
245
246    if( reserved )
247    {
248        if( f->reserved < TR_RESERVED_FDS )
249        {
250            ret = 0;
251            (f->reserved)++;
252        }
253        else
254        {
255            ret = 1;
256        }
257    }
258    else
259    {
260        if( f->normal < f->normalMax )
261        {
262            ret = 0;
263            (f->normal)++;
264        }
265        else
266        {
267            ret = 1;
268        }
269    }
270
271    tr_lockUnlock( &f->lock );
272
273    return ret;
274}
275
276void tr_fdSocketClosed( tr_fd_t * f, int reserved )
277{
278    tr_lockLock( &f->lock );
279
280    if( reserved )
281    {
282        (f->reserved)--;
283    }
284    else
285    {
286        (f->normal)--;
287    }
288
289    tr_lockUnlock( &f->lock );
290}
291
292void tr_fdClose( tr_fd_t * f )
293{
294    tr_lockClose( &f->lock );
295    free( f );
296}
297
Note: See TracBrowser for help on using the repository browser.