Mercurial > projects > ldc
diff tango/lib/common/tango/stdc/posix/pthread_darwin.d @ 132:1700239cab2e trunk
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos.
Lots of bugfixes...
This build is not suitable for most things.
author | lindquist |
---|---|
date | Fri, 11 Jan 2008 17:57:40 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tango/lib/common/tango/stdc/posix/pthread_darwin.d Fri Jan 11 17:57:40 2008 +0100 @@ -0,0 +1,334 @@ +/** + * D header file for POSIX. + * + * Copyright: Public Domain + * License: Public Domain + * Authors: Sean Kelly + * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition + */ +module tango.stdc.posix.pthread; + +public import tango.stdc.posix.sys.types; +public import tango.stdc.posix.sched; +public import tango.stdc.posix.time; +private import tango.stdc.stdlib; + +extern (C): + +// +// Required +// + +version( darwin ) +{ + int pthread_cond_broadcast(pthread_cond_t*); + int pthread_cond_destroy(pthread_cond_t*); + int pthread_cond_init(pthread_cond_t*, pthread_condattr_t*); + //int pthread_cond_signal(pthread_cond_t*); + //int pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, timespec*); + int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*); + + int pthread_mutex_destroy(pthread_mutex_t*); + int pthread_mutex_init(pthread_mutex_t*, pthread_mutexattr_t*); + int pthread_mutex_lock(pthread_mutex_t*); + int pthread_mutex_trylock(pthread_mutex_t*); + int pthread_mutex_unlock(pthread_mutex_t*); + + //int pthread_rwlock_destroy(pthread_rwlock_t*); + //int pthread_rwlock_init(pthread_rwlock_t*, pthread_rwlockattr_t*); + //int pthread_rwlock_rdlock(pthread_rwlock_t*); + int pthread_rwlock_tryrdlock(pthread_rwlock_t*); + int pthread_rwlock_trywrlock(pthread_rwlock_t*); + //int pthread_rwlock_unlock(pthread_rwlock_t*); + //int pthread_rwlock_wrlock(pthread_rwlock_t*); +} + +// +// Barrier (BAR) +// +/* +PTHREAD_BARRIER_SERIAL_THREAD + +int pthread_barrier_destroy(pthread_barrier_t*); +int pthread_barrier_init(pthread_barrier_t*, pthread_barrierattr_t*, uint); +int pthread_barrier_wait(pthread_barrier_t*); +int pthread_barrierattr_destroy(pthread_barrierattr_t*); +int pthread_barrierattr_getpshared(pthread_barrierattr_t*, int*); (BAR|TSH) +int pthread_barrierattr_init(pthread_barrierattr_t*); +int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); (BAR|TSH) +*/ + +version( darwin ) +{ + const PTHREAD_BARRIER_SERIAL_THREAD = -1; + + // defined in tango.stdc.posix.pthread and redefined here + enum + { + PTHREAD_PROCESS_PRIVATE, + PTHREAD_PROCESS_SHARED + } + + int pthread_barrier_destroy( pthread_barrier_t* barrier ) + { + if( barrier is null ) + return EINVAL; + if( barrier.b_waiters > 0 ) + return EBUSY; + int mret = pthread_mutex_destroy( &barrier.b_lock ); + int cret = pthread_cond_destroy( &barrier.b_cond ); + free( barrier ); + return mret ? mret : cret; + } + + int pthread_barrier_init( pthread_barrier_t* barrier, + pthread_barrierattr_t* attr, + uint count ) + { + if( barrier is null || count <= 0 ) + return EINVAL; + + pthread_barrier_t* newbarrier = cast(pthread_barrier_t*) + malloc( pthread_barrier_t.sizeof ); + if( newbarrier is null ) + return ENOMEM; + + int ret; + if( ( ret = pthread_mutex_init( &newbarrier.b_lock, null ) ) != 0 ) + { + free( newbarrier ); + return ret; + } + if( ( ret = pthread_cond_init( &newbarrier.b_cond, null ) ) != 0 ) + { + pthread_mutex_destroy( &newbarrier.b_lock ); + free( newbarrier ); + return ret; + } + newbarrier.b_waiters = 0; + newbarrier.b_count = count; + newbarrier.b_generation = 0; + *barrier = *newbarrier; + + return 0; + } + + int pthread_barrier_wait( pthread_barrier_t* barrier ) + { + if( barrier is null ) + return EINVAL; + + int ret; + if( ( ret = pthread_mutex_lock( &barrier.b_lock ) ) != 0 ) + return ret; + + if( ++barrier.b_waiters == barrier.b_count ) + { + // current thread is lastest thread + barrier.b_generation++; + barrier.b_waiters = 0; + if( ( ret = pthread_cond_broadcast( &barrier.b_cond ) ) == 0 ) + ret = PTHREAD_BARRIER_SERIAL_THREAD; + } + else + { + int gen = barrier.b_generation; + do + { + ret = pthread_cond_wait( &barrier.b_cond, &barrier.b_lock ); + // test generation to avoid bogus wakeup + } while( ret == 0 && gen == barrier.b_generation ); + } + pthread_mutex_unlock( &barrier.b_lock ); + return ret; + } + + int pthread_barrierattr_destroy( pthread_barrierattr_t* attr ) + { + if( attr is null ) + return EINVAL; + free( attr ); + return 0; + } + + int pthread_barrierattr_getpshared( pthread_barrierattr_t* attr, int* pshared ) + { + if( attr is null ) + return EINVAL; + *pshared = attr.pshared; + return 0; + } + + int pthread_barrierattr_init( pthread_barrierattr_t* attr ) + { + if( attr is null ) + return EINVAL; + if( ( attr = cast(pthread_barrierattr_t*) + malloc( pthread_barrierattr_t.sizeof ) ) is null ) + return ENOMEM; + attr.pshared = PTHREAD_PROCESS_PRIVATE; + return 0; + } + + int pthread_barrierattr_setpshared( pthread_barrierattr_t* attr, int pshared ) + { + if( attr is null ) + return EINVAL; + // only PTHREAD_PROCESS_PRIVATE is supported + if( pshared != PTHREAD_PROCESS_PRIVATE ) + return EINVAL; + attr.pshared = pshared; + return 0; + } +} + +// +// Timeouts (TMO) +// +/* +int pthread_mutex_timedlock(pthread_mutex_t*, timespec*); +int pthread_rwlock_timedrdlock(pthread_rwlock_t*, timespec*); +int pthread_rwlock_timedwrlock(pthread_rwlock_t*, timespec*); +*/ + +version( darwin ) +{ + private + { + import tango.stdc.errno; + import tango.stdc.posix.unistd; + import tango.stdc.posix.sys.time; + + extern (D) + { + void timerclear( timeval* tvp ) + { + tvp.tv_sec = tvp.tv_usec = 0; + } + + bool timerisset( timeval* tvp ) + { + return tvp.tv_sec || tvp.tv_usec; + } + + bool timer_cmp_leq( timeval* tvp, timeval* uvp ) + { + return tvp.tv_sec == uvp.tv_sec ? + tvp.tv_usec <= uvp.tv_usec : + tvp.tv_sec <= uvp.tv_sec; + } + + void timeradd( timeval* tvp, timeval* uvp, timeval* vvp ) + { + vvp.tv_sec = tvp.tv_sec + uvp.tv_sec; + vvp.tv_usec = tvp.tv_usec + uvp.tv_usec; + if( vvp.tv_usec >= 1000000 ) + { + vvp.tv_sec++; + vvp.tv_usec -= 1000000; + } + } + + void timersub( timeval* tvp, timeval* uvp, timeval* vvp ) + { + vvp.tv_sec = tvp.tv_sec - uvp.tv_sec; + vvp.tv_usec = tvp.tv_usec - uvp.tv_usec; + if( vvp.tv_usec < 0 ) + { + vvp.tv_sec--; + vvp.tv_usec += 1000000; + } + } + + void TIMEVAL_TO_TIMESPEC( timeval* tv, timespec* ts ) + { + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + } + + void TIMESPEC_TO_TIMEVAL( timeval* tv, timespec* ts ) + { + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; + } + } + } + + int pthread_mutex_timedlock( pthread_mutex_t* m, timespec* t ) + { + timeval currtime; + timeval maxwait; + TIMESPEC_TO_TIMEVAL( &maxwait, t ); + timeval waittime; + waittime.tv_usec = 100; + + while( timer_cmp_leq( &currtime, &maxwait ) ) + { + int ret = pthread_mutex_trylock( m ); + switch( ret ) + { + case 0: // locked successfully + return ret; + case EBUSY: // waiting + timeradd( &currtime, &waittime, &currtime ); + break; + default: + return ret; + } + usleep( waittime.tv_usec ); + } + return ETIMEDOUT; + } + + int pthread_rwlock_timedrdlock( pthread_rwlock_t *rwlock, timespec* t ) + { + timeval currtime; + timeval maxwait; + TIMESPEC_TO_TIMEVAL( &maxwait, t ); + timeval waittime; + waittime.tv_usec = 100; + + while( timer_cmp_leq( &currtime, &maxwait ) ) + { + int ret = pthread_rwlock_tryrdlock( rwlock ); + switch( ret ) + { + case 0: // locked successfully + return ret; + case EBUSY: // waiting + timeradd( &currtime, &waittime, &currtime ); + break; + default: + return ret; + } + usleep( waittime.tv_usec ); + } + return ETIMEDOUT; + } + + int pthread_rwlock_timedwrlock( pthread_rwlock_t* l, timespec* t ) + { + timeval currtime; + timeval maxwait; + TIMESPEC_TO_TIMEVAL( &maxwait, t ); + timeval waittime; + waittime.tv_usec = 100; + + while( timer_cmp_leq( &currtime, &maxwait ) ) + { + int ret = pthread_rwlock_trywrlock( l ); + switch( ret ) + { + case 0: // locked successfully + return ret; + case EBUSY: // waiting + timeradd( &currtime, &waittime, &currtime ); + break; + default: + return ret; + } + usleep( waittime.tv_usec ); + } + return ETIMEDOUT; + } +}