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.