source: trunk/libtransmission/fdlimit.c @ 1

Last change on this file since 1 was 1, checked in by root, 15 years ago

Import from 2005-10-26

File size: 6.5 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    int        status;
38
39    uint64_t   date;
40
41} tr_openFile_t;
42
43struct tr_fd_s
44{
45    tr_lock_t       lock;
46   
47    int             reserved;
48
49    int             normal;
50    int             normalMax;
51
52    tr_openFile_t   open[TR_MAX_OPEN_FILES];
53};
54
55/***********************************************************************
56 * tr_fdInit
57 **********************************************************************/
58tr_fd_t * tr_fdInit()
59{
60    tr_fd_t * f;
61    int i, j, s[4096];
62
63    f = calloc( sizeof( tr_fd_t ), 1 );
64
65    /* Init lock */
66    tr_lockInit( &f->lock );
67
68    /* Detect the maximum number of open files or sockets */
69    for( i = 0; i < 4096; i++ )
70    {
71        if( ( s[i] = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
72        {
73            break;
74        }
75    }
76    for( j = 0; j < i; j++ )
77    {
78        tr_netClose( s[j] );
79    }
80
81    tr_dbg( "%d usable file descriptors", i );
82
83    f->reserved  = 0;
84    f->normal    = 0;
85
86    f->normalMax = i - TR_RESERVED_FDS - 10;
87        /* To be safe, in case the UI needs to write a preferences file
88           or something */
89
90    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
91    {
92        f->open[i].status = STATUS_INVALID;
93    }
94
95    return f;
96}
97
98/***********************************************************************
99 * tr_fdFileOpen
100 **********************************************************************/
101FILE * tr_fdFileOpen( tr_fd_t * f, char * path )
102{
103    int i, winner;
104    uint64_t date;
105
106    tr_lockLock( f->lock );
107
108    /* Is it already open? */
109    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
110    {
111        if( f->open[i].status > STATUS_INVALID &&
112            !strcmp( path, f->open[i].path ) )
113        {
114            winner = i;
115            goto done;
116        }
117    }
118
119    /* Can we open one more file? */
120    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
121    {
122        if( f->open[i].status & STATUS_INVALID )
123        {
124            winner = i;
125            goto open;
126        }
127    }
128
129    for( ;; )
130    {
131        /* Close the oldest currently unused file */
132        date   = tr_date() + 1;
133        winner = -1;
134
135        for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
136        {
137            if( f->open[i].status & STATUS_USED )
138            {
139                continue;
140            }
141            if( f->open[i].date < date )
142            {
143                winner = i;
144                date   = f->open[i].date;
145            }
146        }
147
148        if( winner >= 0 )
149        {
150            tr_dbg( "Closing %s", f->open[winner].path );
151            fclose( f->open[winner].file );
152            goto open;
153        }
154
155        /* All used! Wait a bit and try again */
156        tr_lockUnlock( f->lock );
157        tr_wait( 10 );
158        tr_lockLock( f->lock );
159    }
160
161open:
162    tr_dbg( "Opening %s", path );
163    snprintf( f->open[winner].path, MAX_PATH_LENGTH, "%s", path );
164    f->open[winner].file = fopen( path, "r+" );
165
166done:
167    f->open[winner].status = STATUS_USED;
168    f->open[winner].date   = tr_date();
169    tr_lockUnlock( f->lock );
170   
171    return f->open[winner].file;
172}
173
174/***********************************************************************
175 * tr_fdFileRelease
176 **********************************************************************/
177void tr_fdFileRelease( tr_fd_t * f, FILE * file )
178{
179    int i;
180    tr_lockLock( f->lock );
181
182    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
183    {
184        if( f->open[i].file == file )
185        {
186            f->open[i].status = STATUS_UNUSED;
187            break;
188        }
189    }
190   
191    tr_lockUnlock( f->lock );
192}
193
194/***********************************************************************
195 * tr_fdFileClose
196 **********************************************************************/
197void tr_fdFileClose( tr_fd_t * f, char * path )
198{
199    int i;
200
201    tr_lockLock( f->lock );
202
203    /* Is it already open? */
204    for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
205    {
206        if( f->open[i].status & STATUS_INVALID )
207        {
208            continue;
209        }
210        if( !strcmp( path, f->open[i].path ) )
211        {
212            tr_dbg( "Closing %s", path );
213            fclose( f->open[i].file );
214            f->open[i].status = STATUS_INVALID;
215            break;
216        }
217    }
218
219    tr_lockUnlock( f->lock );
220}
221
222int tr_fdSocketWillCreate( tr_fd_t * f, int reserved )
223{
224    int ret;
225
226    tr_lockLock( f->lock );
227
228    if( reserved )
229    {
230        if( f->reserved < TR_RESERVED_FDS )
231        {
232            ret = 0;
233            (f->reserved)++;
234        }
235        else
236        {
237            ret = 1;
238        }
239    }
240    else
241    {
242        if( f->normal < f->normalMax )
243        {
244            ret = 0;
245            (f->normal)++;
246        }
247        else
248        {
249            ret = 1;
250        }
251    }
252
253    tr_lockUnlock( f->lock );
254
255    return ret;
256}
257
258void tr_fdSocketClosed( tr_fd_t * f, int reserved )
259{
260    tr_lockLock( f->lock );
261
262    if( reserved )
263    {
264        (f->reserved)--;
265    }
266    else
267    {
268        (f->normal)--;
269    }
270
271    tr_lockUnlock( f->lock );
272}
273
274void tr_fdClose( tr_fd_t * f )
275{
276    tr_lockClose( f->lock );
277    free( f );
278}
279
Note: See TracBrowser for help on using the repository browser.