source: trunk/libtransmission/fdlimit.c @ 3

Last change on this file since 3 was 3, checked in by root, 16 years ago

Update 2005-11-17

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