1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-25 09:13:06 +00:00

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

This commit is contained in:
Charles Kerr 2007-12-03 04:06:45 +00:00
parent 7b068ed926
commit c68af92039
3 changed files with 5 additions and 202 deletions

View file

@ -109,7 +109,6 @@ struct tr_fd_s
int normal;
int normalMax;
tr_lock * lock;
tr_cond * cond;
struct tr_openfile open[TR_MAX_OPEN_FILES];
};
@ -180,7 +179,6 @@ TrCloseFile( int i )
close( o->fd );
o->fd = -1;
o->isCheckedOut = 0;
tr_condSignal( gFd->cond );
}
static int
@ -215,7 +213,7 @@ tr_fdFileCheckout( const char * filename, int write )
if( fileIsCheckedOut( o ) ) {
dbgmsg( "found it! it's open, but checked out. waiting..." );
tr_condWait( gFd->cond, gFd->lock );
tr_wait( 100 );
i = -1; /* reloop */
continue;
}
@ -262,7 +260,7 @@ tr_fdFileCheckout( const char * filename, int write )
/* All used! Wait a bit and try again */
dbgmsg( "everything's full! waiting for someone else to finish something" );
tr_condWait( gFd->cond, gFd->lock );
tr_wait( 100 );
}
done:
@ -309,7 +307,6 @@ tr_fdFileReturn( int fd )
break;
}
tr_condSignal( gFd->cond );
tr_lockUnlock( gFd->lock );
}
@ -335,7 +332,6 @@ tr_fdFileClose( const char * filename )
}
}
tr_condSignal( gFd->cond );
tr_lockUnlock( gFd->lock );
}
@ -462,7 +458,6 @@ tr_fdInit( void )
gFd = tr_new0( struct tr_fd_s, 1 );
gFd->lock = tr_lockNew( );
gFd->cond = tr_condNew( );
/* count the max number of sockets we can use */
for( i=0; i<TR_MAX_SOCKETS; ++i )
@ -490,7 +485,6 @@ tr_fdClose( void )
TrCloseFile( i );
tr_lockFree( gFd->lock );
tr_condFree( gFd->cond );
tr_list_free( &reservedSockets, NULL );
tr_free( gFd );

View file

@ -248,10 +248,11 @@ tr_lockLock( tr_lock * l )
#else
pthread_mutex_lock( &l->lock );
#endif
assert( l->depth >= 0 );
if( l->depth )
assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
l->lockThread = tr_getCurrentThread( );
++l->depth;
/* fprintf( stderr, "thread %lu acquired lock %p... depth is now %d\n", (unsigned long)l->lockThread, l, l->depth ); */
assert( l->depth >= 1 );
}
int
@ -264,11 +265,8 @@ tr_lockHave( const tr_lock * l )
void
tr_lockUnlock( tr_lock * l )
{
/* fprintf( stderr, "thread %lu releasing lock %p... depth before release is %d\n", (unsigned long)l->lockThread, l, l->depth ); */
assert( l->depth > 0 );
assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ));
assert( tr_lockHave( l ) );
--l->depth;
assert( l->depth >= 0 );
@ -281,188 +279,6 @@ tr_lockUnlock( tr_lock * l )
#endif
}
/***
**** COND
***/
struct tr_cond
{
#ifdef __BEOS__
sem_id sem;
thread_id threads[BEOS_MAX_THREADS];
int start, end;
#elif defined(WIN32)
tr_list * events;
tr_lock * lock;
#else
pthread_cond_t cond;
#endif
};
#ifdef WIN32
static DWORD getContEventTLS( void )
{
static int inited = FALSE;
static DWORD event_tls;
if( !inited ) {
inited = TRUE;
event_tls = TlsAlloc();
}
return event_tls;
}
#endif
tr_cond*
tr_condNew( void )
{
tr_cond * c = tr_new0( tr_cond, 1 );
#ifdef __BEOS__
c->sem = create_sem( 1, "" );
c->start = 0;
c->end = 0;
#elif defined(WIN32)
c->events = NULL;
c->lock = tr_lockNew( );
#else
pthread_cond_init( &c->cond, NULL );
#endif
return c;
}
void
tr_condWait( tr_cond * c, tr_lock * l )
{
#ifdef __BEOS__
/* Keep track of that thread */
acquire_sem( c->sem );
c->threads[c->end] = find_thread( NULL );
c->end = ( c->end + 1 ) % BEOS_MAX_THREADS;
assert( c->end != c->start ); /* We hit BEOS_MAX_THREADS, arggh */
release_sem( c->sem );
release_sem( l->lock );
suspend_thread( find_thread( NULL ) ); /* Wait for signal */
acquire_sem( l->lock );
#elif defined(WIN32)
/* get this thread's cond event */
DWORD key = getContEventTLS ( );
HANDLE hEvent = TlsGetValue( key );
if( !hEvent ) {
hEvent = CreateEvent( 0, FALSE, FALSE, 0 );
TlsSetValue( key, hEvent );
}
/* add it to the list of events waiting to be signaled */
tr_lockLock( c->lock );
tr_list_append( &c->events, hEvent );
tr_lockUnlock( c->lock );
/* now wait for it to be signaled */
tr_lockUnlock( l );
WaitForSingleObject( hEvent, INFINITE );
tr_lockLock( l );
/* remove it from the list of events waiting to be signaled */
tr_lockLock( c->lock );
tr_list_remove_data( &c->events, hEvent );
tr_lockUnlock( c->lock );
#else
pthread_cond_wait( &c->cond, &l->lock );
#endif
}
#ifdef __BEOS__
static int condTrySignal( tr_cond * c )
{
if( c->start == c->end )
return 1;
for( ;; )
{
thread_info info;
get_thread_info( c->threads[c->start], &info );
if( info.state == B_THREAD_SUSPENDED )
{
resume_thread( c->threads[c->start] );
c->start = ( c->start + 1 ) % BEOS_MAX_THREADS;
break;
}
/* The thread is not suspended yet, which can happen since
* tr_condWait does not atomically suspends after releasing
* the semaphore. Wait a bit and try again. */
snooze( 5000 );
}
return 0;
}
#endif
void
tr_condSignal( tr_cond * c )
{
#ifdef __BEOS__
acquire_sem( c->sem );
condTrySignal( c );
release_sem( c->sem );
#elif defined(WIN32)
tr_lockLock( c->lock );
if( c->events != NULL )
SetEvent( (HANDLE)c->events->data );
tr_lockUnlock( c->lock );
#else
pthread_cond_signal( &c->cond );
#endif
}
void
tr_condBroadcast( tr_cond * c )
{
#ifdef __BEOS__
acquire_sem( c->sem );
while( !condTrySignal( c ) );
release_sem( c->sem );
#elif defined(WIN32)
tr_list * l;
tr_lockLock( c->lock );
for( l=c->events; l!=NULL; l=l->next )
SetEvent( (HANDLE)l->data );
tr_lockUnlock( c->lock );
#else
pthread_cond_broadcast( &c->cond );
#endif
}
void
tr_condFree( tr_cond * c )
{
#ifdef __BEOS__
delete_sem( c->sem );
#elif defined(WIN32)
tr_list_free( &c->events, NULL );
tr_lockFree( c->lock );
#else
pthread_cond_destroy( &c->cond );
#endif
tr_free( c );
}
/***
**** PATHS
***/

View file

@ -25,7 +25,6 @@
#define TR_PLATFORM_H
typedef struct tr_lock tr_lock;
typedef struct tr_cond tr_cond;
typedef struct tr_thread tr_thread;
const char * tr_getHomeDirectory( void );
@ -42,12 +41,6 @@ void tr_lockLock ( tr_lock * );
void tr_lockUnlock ( tr_lock * );
int tr_lockHave ( const tr_lock * );
tr_cond * tr_condNew ( void );
void tr_condFree ( tr_cond * );
void tr_condSignal ( tr_cond * );
void tr_condBroadcast ( tr_cond * );
void tr_condWait ( tr_cond *, tr_lock * );
struct in_addr; /* forward declaration to calm gcc down */
int
tr_getDefaultRoute( struct in_addr * addr );