Changeset 1356 for trunk/libtransmission/fdlimit.c
- Timestamp:
- Jan 14, 2007, 12:00:21 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/fdlimit.c
r261 r1356 31 31 typedef struct tr_openFile_s 32 32 { 33 char path[MAX_PATH_LENGTH]; 33 char folder[MAX_PATH_LENGTH]; 34 char name[MAX_PATH_LENGTH]; 34 35 int file; 36 int write; 35 37 36 38 #define STATUS_INVALID 1 … … 47 49 { 48 50 tr_lock_t lock; 51 tr_cond_t cond; 49 52 50 53 int reserved; … … 57 60 58 61 /*********************************************************************** 62 * Local prototypes 63 **********************************************************************/ 64 static int ErrorFromErrno(); 65 static int OpenFile( tr_fd_t * f, int i, char * folder, char * name, 66 int write ); 67 static void CloseFile( tr_fd_t * f, int i ); 68 69 70 /*********************************************************************** 59 71 * tr_fdInit 60 72 **********************************************************************/ … … 66 78 f = calloc( sizeof( tr_fd_t ), 1 ); 67 79 68 /* Init lock */80 /* Init lock and cond */ 69 81 tr_lockInit( &f->lock ); 82 tr_condInit( &f->cond ); 70 83 71 84 /* Detect the maximum number of open files or sockets */ … … 102 115 * tr_fdFileOpen 103 116 **********************************************************************/ 104 int tr_fdFileOpen( tr_fd_t * f, char * path)105 { 106 int i, winner ;117 int tr_fdFileOpen( tr_fd_t * f, char * folder, char * name, int write ) 118 { 119 int i, winner, ret; 107 120 uint64_t date; 108 121 … … 112 125 for( i = 0; i < TR_MAX_OPEN_FILES; i++ ) 113 126 { 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; 129 150 } 130 151 … … 139 160 } 140 161 162 /* All slots taken - close the oldest currently unused file */ 141 163 for( ;; ) 142 164 { 143 /* Close the oldest currently unused file */144 165 date = tr_date() + 1; 145 166 winner = -1; … … 160 181 if( winner >= 0 ) 161 182 { 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 ); 170 184 goto open; 171 185 } 172 186 173 187 /* All used! Wait a bit and try again */ 188 tr_condWait( &f->cond, &f->lock ); 189 } 190 191 open: 192 if( ( ret = OpenFile( f, winner, folder, name, write ) ) ) 193 { 174 194 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; 183 200 184 201 done: … … 207 224 } 208 225 226 tr_condSignal( &f->cond ); 209 227 tr_lockUnlock( &f->lock ); 210 228 } … … 213 231 * tr_fdFileClose 214 232 **********************************************************************/ 215 void tr_fdFileClose( tr_fd_t * f, char * path)233 void tr_fdFileClose( tr_fd_t * f, char * folder, char * name ) 216 234 { 217 235 int i; … … 219 237 tr_lockLock( &f->lock ); 220 238 221 /* Is it already open? */222 239 for( i = 0; i < TR_MAX_OPEN_FILES; i++ ) 223 240 { … … 226 243 continue; 227 244 } 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 **********************************************************************/ 240 258 int tr_fdSocketWillCreate( tr_fd_t * f, int reserved ) 241 259 { … … 274 292 } 275 293 294 /*********************************************************************** 295 * tr_fdSocketClosed 296 **********************************************************************/ 276 297 void tr_fdSocketClosed( tr_fd_t * f, int reserved ) 277 298 { … … 290 311 } 291 312 313 /*********************************************************************** 314 * tr_fdClose 315 **********************************************************************/ 292 316 void tr_fdClose( tr_fd_t * f ) 293 317 { 294 318 tr_lockClose( &f->lock ); 319 tr_condClose( &f->cond ); 295 320 free( f ); 296 321 } 297 322 323 324 /*********************************************************************** 325 * Local functions 326 **********************************************************************/ 327 328 /*********************************************************************** 329 * ErrorFromErrno 330 **********************************************************************/ 331 static 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 **********************************************************************/ 343 static 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 **********************************************************************/ 411 static 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.