This is locks_priority.c in view mode; [Download] [Up]
/*
* -- FILE: locks_priority.c
* AUTHOR: Michael T. Peterson
*
* Copyright (C) 1994, by Michael T. Peterson
* All rights reserved.
*
* Permission is granted for noncommercial, private use of this software.
* You are expressely prohibited from selling this software, distributing
* this software with (or within) another product, or removing this notice.
*/
#include <utils.h>
#include <locks.h>
#define UNLOCK(l) ((void)pthread_mutex_unlock( &(l) ))
#define LOCK(l) ((void)pthread_mutex_lock( &(l) ))
#define RETURN(s) \
{\
(void) pthread_mutex_unlock( &liblock ); \
return(s); \
}
static pthread_once_t once_block = pthread_once_init;
static int lib_initialized = FALSE;
static pthread_mutex_t liblock;
static void _prio_init( void )
{
pthread_mutex_init( &liblock, NULL );
lib_initialized = TRUE;
}
struct PRIO_LOCK
{
pthread_mutex_t guard_mutex;
pthread_mutex_t prio_mutex;
pthread_cond_t prio_cond;
pthread_t owner_th;
int locked;
long owners_saved_prio;
long prio_ceiling; /* Highest priority blocked thread */
long prio_cond_waiters;
};
int
pthread_priolock_lock_np( const pthread_priolock_t *prio_lock )
{
struct PRIO_LOCK *plock;
int current_prio;
pthread_t self;
pthread_once( &once_block, _prio_init );
if( prio_lock == NULL )
return( ENOLCK );
if((plock = *prio_lock) == NULL )
return( ENOLCK );
self = pthread_self();
pthread_getprio_np( self, ¤t_prio );
/*
* -- If the current ceiling is lower than the calling thread's
* priority, raise the ceiling.
*/
pthread_mutex_lock( &plock->guard_mutex );
if( current_prio > plock->prio_ceiling )
{
plock->prio_ceiling = current_prio;
/*
* -- If the mutex is locked, then raise the priority of the
* the current owner.
*/
if( plock->locked )
pthread_setprio_np( plock->owner_th, current_prio );
}
pthread_mutex_unlock( &plock->guard_mutex );
/*
* Bump the waiter count in the event we are caused to wait while
* another thread is adjusting the priority ceiling of this lock.
* If we don't have to wait, i.e., the lock is currently unlocked,
* no harm done. We just keep on cruisin...
*/
pthread_mutex_lock( &plock->prio_mutex );
plock->prio_cond_waiters += 1;
while( plock->locked )
pthread_cond_wait( &plock->prio_cond, &plock->prio_mutex );
plock->prio_cond_waiters -= 1;
plock->owner_th = self;
plock->locked = TRUE;
if( plock->prio_ceiling > current_prio )
plock->owners_saved_prio = current_prio;
pthread_mutex_unlock( &plock->prio_mutex );
return( SUCCESS );
}
int
pthread_priolock_unlock_np( const pthread_priolock_t *prio_lock )
{
struct PRIO_LOCK *plock;
pthread_once( &once_block, _prio_init );
if( prio_lock == NULL )
return( ENOLCK );
if( (plock = *prio_lock) == NULL)
return( ENOLCK );
pthread_mutex_lock( &plock->prio_mutex );
plock->locked = FALSE;
if( plock->prio_cond_waiters )
pthread_cond_signal( &plock->prio_cond );
else
plock->prio_ceiling = plock->owners_saved_prio;
pthread_setprio_np( pthread_self(), plock->owners_saved_prio );
pthread_mutex_unlock( &plock->prio_mutex );
return( SUCCESS );
}
int
pthread_priolock_init_np( pthread_priolock_t *prio_lock )
{
struct PRIO_LOCK *plock = NULL;
int status;
pthread_once( &once_block, _prio_init );
/*
* If any of the following initialization calls fail, deallocate and
* free all resources that had been initialized up to that point.
*/
plock = (struct PRIO_LOCK *) malloc_r( sizeof( struct PRIO_LOCK ));
if( plock == NULL )
{
prio_lock = NULL;
return( ENOMEM );
}
status = pthread_mutex_init( &plock->guard_mutex, NULL );
if( status != SUCCESS )
{
free_r( plock );
return( status );
}
status = pthread_mutex_init( &plock->prio_mutex, NULL );
if( status != SUCCESS )
{
(void) pthread_mutex_destroy( &plock->guard_mutex );
free_r( plock );
return( status );
}
status = pthread_cond_init( &plock->prio_cond, NULL );
if( status != SUCCESS )
{
(void) pthread_mutex_destroy( &plock->guard_mutex );
(void) pthread_mutex_destroy( &plock->prio_mutex );
free_r( plock );
return( status );
}
plock->prio_ceiling = -1;
plock->owners_saved_prio = -1;
plock->prio_cond_waiters = 0;
*prio_lock = (struct PRIO_LOCK *) plock;
return( SUCCESS );
}
int
pthread_priolock_destroy_np( pthread_priolock_t *prio_lock )
{
struct PRIO_LOCK *plock;
int status = SUCCESS, not_ok = FALSE;
pthread_once( &once_block, _prio_init );
LOCK( liblock );
/*
* This next step dereferences the prio_lock handle AND checks
* whether the handle is still valid. This routine can be
* entered by multiple threads and this check ensures that we
* do not attempt to destroy a priority lock that has already
* been destroyed, perhaps while we were waiting at the previous
* mutex.
*/
if( prio_lock == NULL )
RETURN( ENOLCK );
if( (plock = *prio_lock) == NULL )
RETURN( ENOLCK );
/*
* Return an error (EBUSY) if the priority lock is currently
* in use.
*/
not_ok = plock->locked || plock->prio_cond_waiters;
if( not_ok )
RETURN( EBUSY );
status = pthread_mutex_destroy( &plock->guard_mutex );
if( status != SUCCESS )
RETURN( status );
status = pthread_mutex_destroy( &plock->prio_mutex );
if( status != SUCCESS )
RETURN( status );
status = pthread_cond_destroy( &plock->prio_cond );
if( status != SUCCESS )
RETURN( status );
free_r( plock );
*prio_lock = NULL;
RETURN( status );
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.