Ignore:
Timestamp:
Jul 30, 2007, 3:27:52 PM (14 years ago)
Author:
charles
Message:

better encapsulation of platform-specific constructs: tr_thread_t, tr_cond_t, tr_lock_t

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/platform.c

    r2544 r2552  
    3131  #include <fs_info.h>
    3232  #include <FindDirectory.h>
    33 #endif
     33  #include <kernel/OS.h>
     34  #define BEOS_MAX_THREADS 256
     35#else
     36  #include <pthread.h>
     37#endif
     38
    3439#include <sys/types.h>
    3540#include <dirent.h>
     
    3843
    3944#include "transmission.h"
     45#include "utils.h"
     46
     47/***
     48****  THREADS
     49***/
     50
     51struct tr_thread_s
     52{
     53    void          (* func ) ( void * );
     54    void           * arg;
     55    char           * name;
     56
     57#ifdef SYS_BEOS
     58    thread_id        thread;
     59#else
     60    pthread_t        thread;
     61#endif
     62
     63};
     64
     65static void
     66ThreadFunc( void * _t )
     67{
     68    tr_thread_t * t = _t;
     69    char* name = tr_strdup( t->name );
     70
     71#ifdef SYS_BEOS
     72    /* This is required because on BeOS, SIGINT is sent to each thread,
     73       which kills them not nicely */
     74    signal( SIGINT, SIG_IGN );
     75#endif
     76
     77    tr_dbg( "Thread '%s' started", name );
     78    t->func( t->arg );
     79    tr_dbg( "Thread '%s' exited", name );
     80    tr_free( name );
     81}
     82
     83tr_thread_t *
     84tr_threadNew( void (*func)(void *),
     85              void * arg,
     86              const char * name )
     87{
     88    tr_thread_t * t = tr_new0( tr_thread_t, 1 );
     89    t->func = func;
     90    t->arg  = arg;
     91    t->name = tr_strdup( name );
     92
     93#ifdef SYS_BEOS
     94    t->thread = spawn_thread( (void*)ThreadFunc, name, B_NORMAL_PRIORITY, t );
     95    resume_thread( t->thread );
     96#else
     97    pthread_create( &t->thread, NULL, (void * (*) (void *)) ThreadFunc, t );
     98#endif
     99
     100    return t;
     101}
     102
     103void
     104tr_threadJoin( tr_thread_t * t )
     105{
     106    if( t != NULL )
     107    {
     108#ifdef SYS_BEOS
     109        long exit;
     110        wait_for_thread( t->thread, &exit );
     111#else
     112        pthread_join( t->thread, NULL );
     113#endif
     114
     115        tr_dbg( "Thread '%s' joined", t->name );
     116        tr_free( t->name );
     117        t->name = NULL;
     118        t->func = NULL;
     119        tr_free( t );
     120    }
     121}
     122
     123/***
     124****  LOCKS
     125***/
     126
     127struct tr_lock_s
     128{
     129#ifdef SYS_BEOS
     130    sem_id lock;
     131#else
     132    pthread_mutex_t lock;
     133#endif
     134};
     135
     136tr_lock_t*
     137tr_lockNew( void )
     138{
     139    tr_lock_t * l = tr_new0( tr_lock_t, 1 );
     140
     141#ifdef SYS_BEOS
     142    l->lock = create_sem( 1, "" );
     143#else
     144    pthread_mutex_init( &l->lock, NULL );
     145#endif
     146
     147    return l;
     148}
     149
     150void
     151tr_lockFree( tr_lock_t * l )
     152{
     153#ifdef SYS_BEOS
     154    delete_sem( l->lock );
     155#else
     156    pthread_mutex_destroy( &l->lock );
     157#endif
     158    tr_free( l );
     159}
     160
     161int
     162tr_lockTryLock( tr_lock_t * l )
     163{
     164#ifdef SYS_BEOS
     165    return acquire_sem_etc( l->lock, 1, B_RELATIVE_TIMEOUT, 0 );
     166#else
     167    /* success on zero! */
     168    return pthread_mutex_trylock( &l->lock );
     169#endif
     170}
     171
     172void
     173tr_lockLock( tr_lock_t * l )
     174{
     175#ifdef SYS_BEOS
     176    acquire_sem( l->lock );
     177#else
     178    pthread_mutex_lock( &l->lock );
     179#endif
     180}
     181
     182void
     183tr_lockUnlock( tr_lock_t * l )
     184{
     185#ifdef SYS_BEOS
     186    release_sem( l->lock );
     187#else
     188    pthread_mutex_unlock( &l->lock );
     189#endif
     190}
     191
     192/***
     193****  RW LOCK
     194***/
     195
     196struct tr_rwlock_s
     197{
     198    tr_lock_t * lock;
     199    tr_cond_t * readCond;
     200    tr_cond_t * writeCond;
     201    size_t readCount;
     202    size_t wantToRead;
     203    size_t wantToWrite;
     204    int haveWriter;
     205};
     206
     207static void
     208tr_rwSignal( tr_rwlock_t * rw )
     209{
     210  if ( rw->wantToWrite )
     211    tr_condSignal( rw->writeCond );
     212  else if ( rw->wantToRead )
     213    tr_condBroadcast( rw->readCond );
     214}
     215
     216tr_rwlock_t*
     217tr_rwNew ( void )
     218{
     219    tr_rwlock_t * rw = tr_new0( tr_rwlock_t, 1 );
     220    rw->lock = tr_lockNew( );
     221    rw->readCond = tr_condNew( );
     222    rw->writeCond = tr_condNew( );
     223    return rw;
     224}
     225
     226void
     227tr_rwReaderLock( tr_rwlock_t * rw )
     228{
     229    tr_lockLock( rw->lock );
     230    rw->wantToRead++;
     231    while( rw->haveWriter || rw->wantToWrite )
     232        tr_condWait( rw->readCond, rw->lock );
     233    rw->wantToRead--;
     234    rw->readCount++;
     235    tr_lockUnlock( rw->lock );
     236}
     237
     238int
     239tr_rwReaderTrylock( tr_rwlock_t * rw )
     240{
     241    int ret = FALSE;
     242    tr_lockLock( rw->lock );
     243    if ( !rw->haveWriter && !rw->wantToWrite ) {
     244        rw->readCount++;
     245        ret = TRUE;
     246    }
     247    tr_lockUnlock( rw->lock );
     248    return ret;
     249
     250}
     251
     252void
     253tr_rwReaderUnlock( tr_rwlock_t * rw )
     254{
     255    tr_lockLock( rw->lock );
     256    --rw->readCount;
     257    if( !rw->readCount )
     258        tr_rwSignal( rw );
     259    tr_lockUnlock( rw->lock );
     260}
     261
     262void
     263tr_rwWriterLock( tr_rwlock_t * rw )
     264{
     265    tr_lockLock( rw->lock );
     266    rw->wantToWrite++;
     267    while( rw->haveWriter || rw->readCount )
     268        tr_condWait( rw->writeCond, rw->lock );
     269    rw->wantToWrite--;
     270    rw->haveWriter = TRUE;
     271    tr_lockUnlock( rw->lock );
     272}
     273
     274int
     275tr_rwWriterTrylock( tr_rwlock_t * rw )
     276{
     277    int ret = FALSE;
     278    tr_lockLock( rw->lock );
     279    if( !rw->haveWriter && !rw->readCount )
     280        ret = rw->haveWriter = TRUE;
     281    tr_lockUnlock( rw->lock );
     282    return ret;
     283}
     284void
     285tr_rwWriterUnlock( tr_rwlock_t * rw )
     286{
     287    tr_lockLock( rw->lock );
     288    rw->haveWriter = FALSE;
     289    tr_rwSignal( rw );
     290    tr_lockUnlock( rw->lock );
     291}
     292
     293void
     294tr_rwFree( tr_rwlock_t * rw )
     295{
     296    tr_condFree( rw->writeCond );
     297    tr_condFree( rw->readCond );
     298    tr_lockFree( rw->lock );
     299    tr_free( rw );
     300}
     301
     302/***
     303****  COND
     304***/
     305
     306struct tr_cond_s
     307{
     308#ifdef SYS_BEOS
     309    sem_id sem;
     310    thread_id theads[BEOS_MAX_THREADS];
     311    int start, end;
     312#else
     313    pthread_cond_t cond;
     314#endif
     315};
     316
     317tr_cond_t*
     318tr_condNew( void )
     319{
     320    tr_cond_t * c = tr_new0( tr_cond_t, 1 );
     321#ifdef SYS_BEOS
     322    c->sem = create_sem( 1, "" );
     323    c->start = 0;
     324    c->end = 0;
     325#else
     326    pthread_cond_init( &c->cond, NULL );
     327#endif
     328    return c;
     329}
     330
     331void tr_condWait( tr_cond_t * c, tr_lock_t * l )
     332{
     333#ifdef SYS_BEOS
     334    /* Keep track of that thread */
     335    acquire_sem( c->sem );
     336    c->threads[c->end] = find_thread( NULL );
     337    c->end = ( c->end + 1 ) % BEOS_MAX_THREADS;
     338    assert( c->end != c->start ); /* We hit BEOS_MAX_THREADS, arggh */
     339    release_sem( c->sem );
     340
     341    release_sem( *l );
     342    suspend_thread( find_thread( NULL ) ); /* Wait for signal */
     343    acquire_sem( *l );
     344#else
     345    pthread_cond_wait( &c->cond, &l->lock );
     346#endif
     347}
     348
     349#ifdef SYS_BEOS
     350static int condTrySignal( tr_cond_t * c )
     351{
     352    if( c->start == c->end )
     353        return 1;
     354
     355    for( ;; )
     356    {
     357        thread_info info;
     358        get_thread_info( c->threads[c->start], &info );
     359        if( info.state == B_THREAD_SUSPENDED )
     360        {
     361            resume_thread( c->threads[c->start] );
     362            c->start = ( c->start + 1 ) % BEOS_MAX_THREADS;
     363            break;
     364        }
     365        /* The thread is not suspended yet, which can happen since
     366         * tr_condWait does not atomically suspends after releasing
     367         * the semaphore. Wait a bit and try again. */
     368        snooze( 5000 );
     369    }
     370    return 0;
     371}
     372#endif
     373void tr_condSignal( tr_cond_t * c )
     374{
     375#ifdef SYS_BEOS
     376    acquire_sem( c->sem );
     377    condTrySignal( c );
     378    release_sem( c->sem );
     379#else
     380    pthread_cond_signal( &c->cond );
     381#endif
     382}
     383void tr_condBroadcast( tr_cond_t * c )
     384{
     385#ifdef SYS_BEOS
     386    acquire_sem( c->sem );
     387    while( !condTrySignal( c ) );
     388    release_sem( c->sem );
     389#else
     390    pthread_cond_broadcast( &c->cond );
     391#endif
     392}
     393
     394void
     395tr_condFree( tr_cond_t * c )
     396{
     397#ifdef SYS_BEOS
     398    delete_sem( c->sem );
     399#else
     400    pthread_cond_destroy( &c->cond );
     401#endif
     402    tr_free( c );
     403}
     404
     405
     406/***
     407****  PATHS
     408***/
    40409
    41410#if !defined( SYS_BEOS ) && !defined( __AMIGAOS4__ )
     
    205574}
    206575
    207 static void ThreadFunc( void * _t )
    208 {
    209     tr_thread_t * t = _t;
    210     char* name = tr_strdup( t->name );
    211 
    212 #ifdef SYS_BEOS
    213     /* This is required because on BeOS, SIGINT is sent to each thread,
    214        which kills them not nicely */
    215     signal( SIGINT, SIG_IGN );
    216 #endif
    217 
    218     tr_dbg( "Thread '%s' started", name );
    219     t->func( t->arg );
    220     tr_dbg( "Thread '%s' exited", name );
    221     tr_free( name );
    222 }
    223 
    224 void tr_threadCreate( tr_thread_t * t,
    225                       void (*func)(void *), void * arg,
    226                       const char * name )
    227 {
    228     t->func = func;
    229     t->arg  = arg;
    230     t->name = tr_strdup( name );
    231 #ifdef SYS_BEOS
    232     t->thread = spawn_thread( (void *) ThreadFunc, name,
    233                               B_NORMAL_PRIORITY, t );
    234     resume_thread( t->thread );
    235 #else
    236     pthread_create( &t->thread, NULL, (void * (*) (void *)) ThreadFunc, t );
    237 #endif
    238 }
    239 
    240 const tr_thread_t THREAD_EMPTY = { NULL, NULL, NULL, 0 };
    241 
    242 void tr_threadJoin( tr_thread_t * t )
    243 {
    244     if( t->func != NULL )
    245     {
    246 #ifdef SYS_BEOS
    247         long exit;
    248         wait_for_thread( t->thread, &exit );
    249 #else
    250         pthread_join( t->thread, NULL );
    251 #endif
    252         tr_dbg( "Thread '%s' joined", t->name );
    253         tr_free( t->name );
    254         t->name = NULL;
    255         t->func = NULL;
    256     }
    257 }
    258 
    259 void tr_lockInit( tr_lock_t * l )
    260 {
    261 #ifdef SYS_BEOS
    262     *l = create_sem( 1, "" );
    263 #else
    264     pthread_mutex_init( l, NULL );
    265 #endif
    266 }
    267 
    268 void tr_lockClose( tr_lock_t * l )
    269 {
    270 #ifdef SYS_BEOS
    271     delete_sem( *l );
    272 #else
    273     pthread_mutex_destroy( l );
    274 #endif
    275 }
    276 
    277 int tr_lockTryLock( tr_lock_t * l )
    278 {
    279 #ifdef SYS_BEOS
    280     return acquire_sem_etc( *l, 1, B_RELATIVE_TIMEOUT, 0 );
    281 #else
    282     /* success on zero! */
    283     return pthread_mutex_trylock( l );
    284 #endif
    285 }
    286 
    287 void tr_lockLock( tr_lock_t * l )
    288 {
    289 #ifdef SYS_BEOS
    290     acquire_sem( *l );
    291 #else
    292     pthread_mutex_lock( l );
    293 #endif
    294 }
    295 
    296 void tr_lockUnlock( tr_lock_t * l )
    297 {
    298 #ifdef SYS_BEOS
    299     release_sem( *l );
    300 #else
    301     pthread_mutex_unlock( l );
    302 #endif
    303 }
    304 
    305 
    306 void tr_condInit( tr_cond_t * c )
    307 {
    308 #ifdef SYS_BEOS
    309     c->sem = create_sem( 1, "" );
    310     c->start = 0;
    311     c->end = 0;
    312 #else
    313     pthread_cond_init( c, NULL );
    314 #endif
    315 }
    316 
    317 void tr_condWait( tr_cond_t * c, tr_lock_t * l )
    318 {
    319 #ifdef SYS_BEOS
    320     /* Keep track of that thread */
    321     acquire_sem( c->sem );
    322     c->threads[c->end] = find_thread( NULL );
    323     c->end = ( c->end + 1 ) % BEOS_MAX_THREADS;
    324     assert( c->end != c->start ); /* We hit BEOS_MAX_THREADS, arggh */
    325     release_sem( c->sem );
    326 
    327     release_sem( *l );
    328     suspend_thread( find_thread( NULL ) ); /* Wait for signal */
    329     acquire_sem( *l );
    330 #else
    331     pthread_cond_wait( c, l );
    332 #endif
    333 }
    334 
    335 #ifdef SYS_BEOS
    336 static int condTrySignal( tr_cond_t * c )
    337 {
    338     if( c->start == c->end )
    339         return 1;
    340 
    341     for( ;; )
    342     {
    343         thread_info info;
    344         get_thread_info( c->threads[c->start], &info );
    345         if( info.state == B_THREAD_SUSPENDED )
    346         {
    347             resume_thread( c->threads[c->start] );
    348             c->start = ( c->start + 1 ) % BEOS_MAX_THREADS;
    349             break;
    350         }
    351         /* The thread is not suspended yet, which can happen since
    352          * tr_condWait does not atomically suspends after releasing
    353          * the semaphore. Wait a bit and try again. */
    354         snooze( 5000 );
    355     }
    356     return 0;
    357 }
    358 #endif
    359 void tr_condSignal( tr_cond_t * c )
    360 {
    361 #ifdef SYS_BEOS
    362     acquire_sem( c->sem );
    363     condTrySignal( c );
    364     release_sem( c->sem );
    365 #else
    366     pthread_cond_signal( c );
    367 #endif
    368 }
    369 void tr_condBroadcast( tr_cond_t * c )
    370 {
    371 #ifdef SYS_BEOS
    372     acquire_sem( c->sem );
    373     while( !condTrySignal( c ) );
    374     release_sem( c->sem );
    375 #else
    376     pthread_cond_broadcast( c );
    377 #endif
    378 }
    379 
    380 void tr_condClose( tr_cond_t * c )
    381 {
    382 #ifdef SYS_BEOS
    383     delete_sem( c->sem );
    384 #else
    385     pthread_cond_destroy( c );
    386 #endif
    387 }
    388 
    389 
    390 #if defined( BSD )
     576/***
     577****  SOCKETS
     578***/
     579
     580#ifdef BSD
    391581
    392582#include <sys/types.h>
     
    760950
    761951#endif
    762 
    763 /***
    764 ****
    765 ***/
    766 
    767 static void
    768 tr_rwSignal( tr_rwlock_t * rw )
    769 {
    770   if ( rw->wantToWrite )
    771     tr_condSignal( &rw->writeCond );
    772   else if ( rw->wantToRead )
    773     tr_condBroadcast( &rw->readCond );
    774 }
    775 
    776 void
    777 tr_rwInit ( tr_rwlock_t * rw )
    778 {
    779     memset( rw, 0, sizeof(tr_rwlock_t) );
    780     tr_lockInit( &rw->lock );
    781     tr_condInit( &rw->readCond );
    782     tr_condInit( &rw->writeCond );
    783 }
    784 
    785 void
    786 tr_rwReaderLock( tr_rwlock_t * rw )
    787 {
    788     tr_lockLock( &rw->lock );
    789     rw->wantToRead++;
    790     while( rw->haveWriter || rw->wantToWrite )
    791         tr_condWait( &rw->readCond, &rw->lock );
    792     rw->wantToRead--;
    793     rw->readCount++;
    794     tr_lockUnlock( &rw->lock );
    795 }
    796 
    797 int
    798 tr_rwReaderTrylock( tr_rwlock_t * rw )
    799 {
    800     int ret = FALSE;
    801     tr_lockLock( &rw->lock );
    802     if ( !rw->haveWriter && !rw->wantToWrite ) {
    803         rw->readCount++;
    804         ret = TRUE;
    805     }
    806     tr_lockUnlock( &rw->lock );
    807     return ret;
    808 
    809 }
    810 
    811 void
    812 tr_rwReaderUnlock( tr_rwlock_t * rw )
    813 {
    814     tr_lockLock( &rw->lock );
    815     --rw->readCount;
    816     if( !rw->readCount )
    817         tr_rwSignal( rw );
    818     tr_lockUnlock( &rw->lock );
    819 }
    820 
    821 void
    822 tr_rwWriterLock( tr_rwlock_t * rw )
    823 {
    824     tr_lockLock( &rw->lock );
    825     rw->wantToWrite++;
    826     while( rw->haveWriter || rw->readCount )
    827         tr_condWait( &rw->writeCond, &rw->lock );
    828     rw->wantToWrite--;
    829     rw->haveWriter = TRUE;
    830     tr_lockUnlock( &rw->lock );
    831 }
    832 
    833 int
    834 tr_rwWriterTrylock( tr_rwlock_t * rw )
    835 {
    836     int ret = FALSE;
    837     tr_lockLock( &rw->lock );
    838     if( !rw->haveWriter && !rw->readCount )
    839         ret = rw->haveWriter = TRUE;
    840     tr_lockUnlock( &rw->lock );
    841     return ret;
    842 }
    843 void
    844 tr_rwWriterUnlock( tr_rwlock_t * rw )
    845 {
    846     tr_lockLock( &rw->lock );
    847     rw->haveWriter = FALSE;
    848     tr_rwSignal( rw );
    849     tr_lockUnlock( &rw->lock );
    850 }
    851 
    852 void
    853 tr_rwClose( tr_rwlock_t * rw )
    854 {
    855     tr_condClose( &rw->writeCond );
    856     tr_condClose( &rw->readCond );
    857     tr_lockClose( &rw->lock );
    858 }
Note: See TracChangeset for help on using the changeset viewer.