Changeset 4043


Ignore:
Timestamp:
Dec 3, 2007, 4:06:45 AM (13 years ago)
Author:
charles
Message:

fix very annoying recursive mutex + pthread cond bug reported by setatg, Waldorf, and many others

Location:
trunk/libtransmission
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/fdlimit.c

    r3918 r4043  
    110110    int                  normalMax;
    111111    tr_lock            * lock;
    112     tr_cond            * cond;
    113112    struct tr_openfile   open[TR_MAX_OPEN_FILES];
    114113};
     
    181180    o->fd = -1;
    182181    o->isCheckedOut = 0;
    183     tr_condSignal( gFd->cond );
    184182}
    185183
     
    216214        if( fileIsCheckedOut( o ) ) {
    217215            dbgmsg( "found it!  it's open, but checked out.  waiting..." );
    218             tr_condWait( gFd->cond, gFd->lock );
     216            tr_wait( 100 );
    219217            i = -1; /* reloop */
    220218            continue;
     
    263261        /* All used! Wait a bit and try again */
    264262        dbgmsg( "everything's full!  waiting for someone else to finish something" );
    265         tr_condWait( gFd->cond, gFd->lock );
     263        tr_wait( 100 );
    266264    }
    267265
     
    310308    }
    311309   
    312     tr_condSignal( gFd->cond );
    313310    tr_lockUnlock( gFd->lock );
    314311}
     
    336333    }
    337334   
    338     tr_condSignal( gFd->cond );
    339335    tr_lockUnlock( gFd->lock );
    340336}
     
    463459    gFd = tr_new0( struct tr_fd_s, 1 );
    464460    gFd->lock = tr_lockNew( );
    465     gFd->cond = tr_condNew( );
    466461
    467462    /* count the max number of sockets we can use */
     
    491486
    492487    tr_lockFree( gFd->lock );
    493     tr_condFree( gFd->cond );
    494488
    495489    tr_list_free( &reservedSockets, NULL );
  • trunk/libtransmission/platform.c

    r4042 r4043  
    249249    pthread_mutex_lock( &l->lock );
    250250#endif
     251    assert( l->depth >= 0 );
     252    if( l->depth )
     253        assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
    251254    l->lockThread = tr_getCurrentThread( );
    252255    ++l->depth;
    253 /* fprintf( stderr, "thread %lu acquired lock %p... depth is now %d\n", (unsigned long)l->lockThread, l, l->depth ); */
    254     assert( l->depth >= 1 );
    255256}
    256257
     
    265266tr_lockUnlock( tr_lock * l )
    266267{
    267 /* fprintf( stderr, "thread %lu releasing lock %p... depth before release is %d\n", (unsigned long)l->lockThread, l, l->depth ); */
    268 
    269268    assert( l->depth > 0 );
    270269    assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ));
    271     assert( tr_lockHave( l ) );
    272270
    273271    --l->depth;
     
    281279#endif
    282280}
    283 
    284 /***
    285 ****  COND
    286 ***/
    287 
    288 struct tr_cond
    289 {
    290 #ifdef __BEOS__
    291     sem_id sem;
    292     thread_id threads[BEOS_MAX_THREADS];
    293     int start, end;
    294 #elif defined(WIN32)
    295     tr_list * events;
    296     tr_lock * lock;
    297 #else
    298     pthread_cond_t cond;
    299 #endif
    300 };
    301 
    302 #ifdef WIN32
    303 static DWORD getContEventTLS( void )
    304 {
    305     static int inited = FALSE;
    306     static DWORD event_tls;
    307     if( !inited ) {
    308         inited = TRUE;
    309         event_tls = TlsAlloc();
    310     }
    311     return event_tls;
    312 }
    313 #endif
    314 
    315 tr_cond*
    316 tr_condNew( void )
    317 {
    318     tr_cond * c = tr_new0( tr_cond, 1 );
    319 #ifdef __BEOS__
    320     c->sem = create_sem( 1, "" );
    321     c->start = 0;
    322     c->end = 0;
    323 #elif defined(WIN32)
    324     c->events = NULL;
    325     c->lock = tr_lockNew( );
    326 #else
    327     pthread_cond_init( &c->cond, NULL );
    328 #endif
    329     return c;
    330 }
    331 
    332 void
    333 tr_condWait( tr_cond * c, tr_lock * l )
    334 {
    335 #ifdef __BEOS__
    336 
    337     /* Keep track of that thread */
    338     acquire_sem( c->sem );
    339     c->threads[c->end] = find_thread( NULL );
    340     c->end = ( c->end + 1 ) % BEOS_MAX_THREADS;
    341     assert( c->end != c->start ); /* We hit BEOS_MAX_THREADS, arggh */
    342     release_sem( c->sem );
    343 
    344     release_sem( l->lock );
    345     suspend_thread( find_thread( NULL ) ); /* Wait for signal */
    346     acquire_sem( l->lock );
    347 
    348 #elif defined(WIN32)
    349 
    350     /* get this thread's cond event */
    351     DWORD key = getContEventTLS ( );
    352     HANDLE hEvent = TlsGetValue( key );
    353     if( !hEvent ) {
    354         hEvent = CreateEvent( 0, FALSE, FALSE, 0 );
    355         TlsSetValue( key, hEvent );
    356     }
    357 
    358     /* add it to the list of events waiting to be signaled */
    359     tr_lockLock( c->lock );
    360     tr_list_append( &c->events, hEvent );
    361     tr_lockUnlock( c->lock );
    362 
    363     /* now wait for it to be signaled */
    364     tr_lockUnlock( l );
    365     WaitForSingleObject( hEvent, INFINITE );
    366     tr_lockLock( l );
    367 
    368     /* remove it from the list of events waiting to be signaled */
    369     tr_lockLock( c->lock );
    370     tr_list_remove_data( &c->events, hEvent );
    371     tr_lockUnlock( c->lock );
    372 
    373 #else
    374 
    375     pthread_cond_wait( &c->cond, &l->lock );
    376 
    377 #endif
    378 }
    379 
    380 #ifdef __BEOS__
    381 static int condTrySignal( tr_cond * c )
    382 {
    383     if( c->start == c->end )
    384         return 1;
    385 
    386     for( ;; )
    387     {
    388         thread_info info;
    389         get_thread_info( c->threads[c->start], &info );
    390         if( info.state == B_THREAD_SUSPENDED )
    391         {
    392             resume_thread( c->threads[c->start] );
    393             c->start = ( c->start + 1 ) % BEOS_MAX_THREADS;
    394             break;
    395         }
    396         /* The thread is not suspended yet, which can happen since
    397          * tr_condWait does not atomically suspends after releasing
    398          * the semaphore. Wait a bit and try again. */
    399         snooze( 5000 );
    400     }
    401     return 0;
    402 }
    403 #endif
    404 void
    405 tr_condSignal( tr_cond * c )
    406 {
    407 #ifdef __BEOS__
    408 
    409     acquire_sem( c->sem );
    410     condTrySignal( c );
    411     release_sem( c->sem );
    412 
    413 #elif defined(WIN32)
    414 
    415     tr_lockLock( c->lock );
    416     if( c->events != NULL )
    417         SetEvent( (HANDLE)c->events->data );
    418     tr_lockUnlock( c->lock );
    419 
    420 #else
    421 
    422     pthread_cond_signal( &c->cond );
    423 
    424 #endif
    425 }
    426 
    427 void
    428 tr_condBroadcast( tr_cond * c )
    429 {
    430 #ifdef __BEOS__
    431 
    432     acquire_sem( c->sem );
    433     while( !condTrySignal( c ) );
    434     release_sem( c->sem );
    435 
    436 #elif defined(WIN32)
    437 
    438     tr_list * l;
    439     tr_lockLock( c->lock );
    440     for( l=c->events; l!=NULL; l=l->next )
    441         SetEvent( (HANDLE)l->data );
    442     tr_lockUnlock( c->lock );
    443 
    444 #else
    445 
    446     pthread_cond_broadcast( &c->cond );
    447 
    448 #endif
    449 }
    450 
    451 void
    452 tr_condFree( tr_cond * c )
    453 {
    454 #ifdef __BEOS__
    455     delete_sem( c->sem );
    456 #elif defined(WIN32)
    457     tr_list_free( &c->events, NULL );
    458     tr_lockFree( c->lock );
    459 #else
    460     pthread_cond_destroy( &c->cond );
    461 #endif
    462     tr_free( c );
    463 }
    464 
    465281
    466282/***
  • trunk/libtransmission/platform.h

    r4001 r4043  
    2626
    2727typedef struct tr_lock   tr_lock;
    28 typedef struct tr_cond   tr_cond;
    2928typedef struct tr_thread tr_thread;
    3029
     
    4342int          tr_lockHave       ( const tr_lock * );
    4443
    45 tr_cond *    tr_condNew       ( void );
    46 void         tr_condFree      ( tr_cond * );
    47 void         tr_condSignal    ( tr_cond * );
    48 void         tr_condBroadcast ( tr_cond * );
    49 void         tr_condWait      ( tr_cond *, tr_lock * );
    50 
    5144struct in_addr; /* forward declaration to calm gcc down */
    5245int
Note: See TracChangeset for help on using the changeset viewer.