Beispiel #1
0
/** Unlock mutex.
 *
 * Thread cancellation is enabled again after the mutex is properly unlocked.
 */
PaError PaUnixMutex_Unlock( PaUnixMutex* self )
{
    PaError result = paNoError;
    int oldState;

    PA_ENSURE_SYSTEM( pthread_mutex_unlock( &self->mtx ), 0 );
    PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 );

error:
    return result;
}
Beispiel #2
0
PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult )
{
    PaError result = paNoError;
    void* pret;

    if( exitResult )
    {
        *exitResult = paNoError;
    }
#if 0
    if( watchdogExitResult )
        *watchdogExitResult = paNoError;

    if( th->watchdogRunning )
    {
        pthread_cancel( th->watchdogThread );
        PA_ENSURE_SYSTEM( pthread_join( th->watchdogThread, &pret ), 0 );

        if( pret && pret != PTHREAD_CANCELED )
        {
            if( watchdogExitResult )
                *watchdogExitResult = *(PaError *) pret;
            free( pret );
        }
    }
#endif

    /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
    /* TODO: Make join time out */
    self->stopRequested = wait;
    if( !wait )
    {
        PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, self->thread ));
        /* XXX: Safe to call this if the thread has exited on its own? */
        pthread_cancel( self->thread );
    }
    PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, self->thread ));
    PA_ENSURE_SYSTEM( pthread_join( self->thread, &pret ), 0 );

    if( pret && PTHREAD_CANCELED != pret )
    {
        if( exitResult )
        {
            *exitResult = *(PaError*)pret;
        }
        free( pret );
    }

error:
    PA_ASSERT_CALL( PaUnixMutex_Terminate( &self->mtx ), paNoError );
    PA_ASSERT_CALL( pthread_cond_destroy( &self->cond ), 0 );

    return result;
}
Beispiel #3
0
/** Lock mutex.
 *
 * We're disabling thread cancellation while the thread is holding a lock, so mutexes are 
 * properly unlocked at termination time.
 */
PaError PaUnixMutex_Lock( PaUnixMutex* self )
{
    PaError result = paNoError;
    
#ifdef PTHREAD_CANCEL
	int oldState;
    PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 );
#endif
    PA_ENSURE_SYSTEM( pthread_mutex_lock( &self->mtx ), 0 );

error:
    return result;
}
Beispiel #4
0
PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild,
        int rtSched )
{
    PaError result = paNoError;
    pthread_attr_t attr;
    int started = 0;

    memset( self, 0, sizeof (PaUnixThread) );
    PaUnixMutex_Initialize( &self->mtx );
    PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 );

    self->parentWaiting = 0 != waitForChild;

    /* Spawn thread */

/* Temporarily disabled since we should test during configuration for presence of required mman.h header */
#if 0
#if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)
    if( rtSched )
    {
        if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 )
        {
            int savedErrno = errno;             /* In case errno gets overwritten */
            assert( savedErrno != EINVAL );     /* Most likely a programmer error */
            PA_UNLESS( (savedErrno == EPERM), paInternalError );
            PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ ));
        }
        else
            PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ ));
    }
#endif
#endif

    PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
    /* Priority relative to other processes */
    PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );   

    PA_UNLESS( !pthread_create( &self->thread, &attr, threadFunc, threadArg ), paInternalError );
    started = 1;

    if( rtSched )
    {
#if 0
        if( self->useWatchdog )
        {
            int err;
            struct sched_param wdSpm = { 0 };
            /* Launch watchdog, watchdog sets callback thread priority */
            int prio = PA_MIN( self->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) );
            wdSpm.sched_priority = prio;

            PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
            PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError );
            PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
            PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError );
            PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError );
            if( (err = pthread_create( &self->watchdogThread, &attr, &WatchdogFunc, self )) )
            {
                PA_UNLESS( err == EPERM, paInternalError );
                /* Permission error, go on without realtime privileges */
                PA_DEBUG(( "Failed bumping priority\n" ));
            }
            else
            {
                int policy;
                self->watchdogRunning = 1;
                PA_ENSURE_SYSTEM( pthread_getschedparam( self->watchdogThread, &policy, &wdSpm ), 0 );
                /* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */
                if( wdSpm.sched_priority != prio )
                {
                    PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority ));
                    PA_ENSURE( paInternalError );
                }
            }
        }
        else
#endif
            PA_ENSURE( BoostPriority( self ) );

        {
            int policy;
            struct sched_param spm;
            pthread_getschedparam(self->thread, &policy, &spm);
        }
    }
    
    if( self->parentWaiting )
    {
        PaTime till;
        struct timespec ts;
        int res = 0;
        PaTime now;

        PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );

        /* Wait for stream to be started */
        now = PaUtil_GetTime();
        till = now + waitForChild;

        while( self->parentWaiting && !res )
        {
            if( waitForChild > 0 )
            {
                ts.tv_sec = (time_t) floor( till );
                ts.tv_nsec = (long) ((till - floor( till )) * 1e9);
                res = pthread_cond_timedwait( &self->cond, &self->mtx.mtx, &ts );
            }
            else
            {
                res = pthread_cond_wait( &self->cond, &self->mtx.mtx );
            }
        }

        PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) );

        PA_UNLESS( !res || ETIMEDOUT == res, paInternalError );
        PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - now ));
        if( ETIMEDOUT == res )
        {
            PA_ENSURE( paTimedOut );
        }
    }

end:
    return result;
error:
    if( started )
    {
        PaUnixThread_Terminate( self, 0, NULL );
    }

    goto end;
}