ftp.nice.ch/Attic/openStep/implementation/gnustep/sources/alpha-snapshots/pthreads.0.9.2.tgz#/pthreads-0.9.2/locklib/locks_shared.c

This is locks_shared.c in view mode; [Download] [Up]

/*
 * --  FILE:           locks_shared.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>

static const int WRITER_ACTIVE = -1;
static const int NO_THREAD_ACTIVE = 0;

static pthread_once_t once_block = pthread_once_init;
static int lib_initialized = FALSE;
static pthread_mutex_t liblock;

#define UNLOCK(l)  ((void)pthread_mutex_unlock( &(l) ))
#define LOCK(l)    ((void)pthread_mutex_lock( &(l) ))

struct SHARED_LOCK
{
   int Activity;
   int ReaderCount;        /* The count of Readers waiting at 'Shared' */
   int WriterCount;        /* The count of Writers waiting at 'Exclusive */
   
   pthread_mutex_t Lock;
   pthread_cond_t  Exclusive;
   pthread_cond_t  Shared;
};


static void 
_rw_init( void )
{
   pthread_mutex_init( &liblock, NULL );
   lib_initialized = TRUE;
}

int
pthread_rw_lock_shared_np( const pthread_rwlock_t *lock )
{
   struct SHARED_LOCK *sh;

   pthread_once( &once_block, _rw_init );

   if( lock == NULL )
       return( ENOLCK );

   if( (sh = *lock) == NULL )
       return( ENOLCK );
   
   pthread_mutex_lock( &sh->Lock );
   
       sh->ReaderCount+= 1;
       
       /*
        *  --  If a writer is waiting to access the shared data, signal it
        *      to proceed then block.  It will wake up the reader upon the
        *      writer's completion.
        */
       if( sh->WriterCount > 0 )
       {
           pthread_cond_signal( &sh->Exclusive );
           pthread_cond_wait( &sh->Shared, &sh->Lock );
       }
       

       while( sh->Activity < 0 )
           pthread_cond_wait( &sh->Shared, &sh->Lock );

       sh->ReaderCount -= 1;
       sh->Activity += 1;

   pthread_mutex_unlock( &sh->Lock );
   pthread_cond_signal( &sh->Shared );

   return( SUCCESS );
}

int
pthread_rw_unlock_exclusive_np( const pthread_rwlock_t *lock )
{
   struct SHARED_LOCK *sh;

   pthread_once( &once_block, _rw_init );

   if( lock == NULL )
       return( ENOLCK );

   if( (sh = *lock) == NULL )
       return( ENOLCK );

   pthread_mutex_lock( &sh->Lock );

       sh->Activity = NO_THREAD_ACTIVE;
       if( sh->ReaderCount > 0 )
           pthread_cond_broadcast( &sh->Shared );
       else
       {
           if( sh->WriterCount > 0 )
               pthread_cond_signal( &sh->Exclusive );
       }

   pthread_mutex_unlock( &sh->Lock );
   return( SUCCESS );
}

int
pthread_rw_lock_exclusive_np( const pthread_rwlock_t *lock )
{
   struct SHARED_LOCK *sh;

   pthread_once( &once_block, _rw_init );
   if( lock == NULL )
       return( ENOLCK );

   if( (sh = *lock) == NULL )
       return( ENOLCK );

   pthread_mutex_lock( &sh->Lock );
   
       sh->WriterCount += 1;
       while( sh->Activity != 0 )
           pthread_cond_wait( &sh->Exclusive, &sh->Lock );

       sh->WriterCount -= 1;
       sh->Activity = WRITER_ACTIVE;

   pthread_mutex_unlock( &sh->Lock );
   return( SUCCESS );
}

int
pthread_rw_unlock_shared_np( const pthread_rwlock_t *lock )
{
   int DoSignal = FALSE;
   struct SHARED_LOCK *sh;

   pthread_once( &once_block, _rw_init );

   if( lock == NULL )
       return( ENOLCK );

   if( (sh = *lock) == NULL )
       return( ENOLCK );
   
   pthread_mutex_lock( &sh->Lock );

       sh->Activity -= 1;

       if( sh->Activity == NO_THREAD_ACTIVE )
           DoSignal = TRUE;

   pthread_mutex_unlock( &sh->Lock );
   
   if( DoSignal )
       pthread_cond_signal( &sh->Exclusive );

   return( SUCCESS );
}

int
pthread_rw_init_np( pthread_rwlock_t *shared )
{
   struct SHARED_LOCK *sh;
   int status;

   pthread_once( &once_block, _rw_init );

   sh = (struct SHARED_LOCK *) malloc_r( sizeof( struct SHARED_LOCK ));
   if( sh == NULL )
       return( ENOMEM );

   sh->Activity = 0;
   sh->ReaderCount = 0;
   sh->WriterCount = 0;

   status = pthread_mutex_init( &sh->Lock, NULL );
   if( status != SUCCESS )
   {
       free_r( sh );
       return( status );
   }

   status = pthread_cond_init( &sh->Exclusive, NULL );
   if( status != SUCCESS )
   {
       (void) pthread_mutex_destroy( &sh->Lock );
       free_r( sh );
       return( status );
   }

   status = pthread_cond_init( &sh->Shared, NULL );
   if( status != SUCCESS )
   {
       (void) pthread_mutex_destroy( &sh->Lock );
       (void) pthread_cond_destroy( &sh->Exclusive );
       free_r( sh );
       return( status );
   }

   *shared = sh;
   return( SUCCESS );
}

int
pthread_rw_destroy_np( pthread_rwlock_t *lock )
{
   struct SHARED_LOCK *sh;

   pthread_once( &once_block, _rw_init );
   LOCK(liblock);
   if( lock == NULL )
       return( ENOLCK );

   if( (sh = *lock) == NULL )
       return( ENOLCK );

   pthread_mutex_destroy( &sh->Lock );
   pthread_cond_destroy( &sh->Exclusive );
   pthread_cond_destroy( &sh->Shared );

   free_r( sh );
   *lock = NULL;
   UNLOCK(liblock);
   return( SUCCESS );
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.