You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by dr...@apache.org on 2001/06/17 21:54:42 UTC

cvs commit: apr/locks/beos locks.c

dreid       01/06/17 12:54:42

  Modified:    include/arch/beos locks.h
               locks/beos locks.c
  Log:
  Add a read/write locking implementation for BeOS.
  
  Revision  Changes    Path
  1.18      +12 -2     apr/include/arch/beos/locks.h
  
  Index: locks.h
  ===================================================================
  RCS file: /home/cvs/apr/include/arch/beos/locks.h,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- locks.h	2001/06/11 11:41:14	1.17
  +++ locks.h	2001/06/17 19:54:40	1.18
  @@ -69,8 +69,18 @@
       apr_os_thread_t owner;
       int owner_ref;
   
  -    sem_id sem;
  -    int32  ben;
  +    /* Our lock :) */
  +    sem_id Lock;
  +    int32  LockCount;
  +
  +    /* Read/Write lock stuff */
  +    sem_id Read;
  +    int32  ReadCount;
  +    sem_id Write;
  +    int32  WriteCount;
  +    int32  Nested;
  +
  +    thread_id writer;
   };
   
   #endif  /* LOCKS_H */
  
  
  
  1.32      +193 -29   apr/locks/beos/locks.c
  
  Index: locks.c
  ===================================================================
  RCS file: /home/cvs/apr/locks/beos/locks.c,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- locks.c	2001/06/11 11:33:36	1.31
  +++ locks.c	2001/06/17 19:54:41	1.32
  @@ -52,51 +52,101 @@
    * <http://www.apache.org/>.
    */
   
  +/*Read/Write locking implementation based on the MultiLock code from
  + * Stephen Beaulieu <hi...@be.com>
  + */
  + 
   #include "beos/locks.h"
   #include "apr_strings.h"
   #include "apr_portable.h"
   
  +#define BIG_NUM 100000
   
  -/* At present we only have one implementation, so here it is :) */
   static apr_status_t _lock_cleanup(void * data)
   {
       apr_lock_t *lock = (apr_lock_t*)data;
  -    if (lock->ben != 0) {
  +    if (lock->LockCount != 0) {
           /* we're still locked... */
  -    	while (atomic_add(&lock->ben , -1) > 1){
  +    	while (atomic_add(&lock->LockCount , -1) > 1){
       	    /* OK we had more than one person waiting on the lock so 
       	     * the sem is also locked. Release it until we have no more
       	     * locks left.
       	     */
  -            release_sem (lock->sem);
  +            release_sem (lock->Lock);
       	}
       }
  -    delete_sem(lock->sem);
  +    delete_sem(lock->Lock);
       return APR_SUCCESS;
   }    
   
  +static apr_status_t _lock_rw_cleanup(void * data)
  +{
  +    apr_lock_t *lock = (apr_lock_t*)data;
  +
  +    if (lock->ReadCount != 0) {
  +    	while (atomic_add(&lock->ReadCount , -1) > 1){
  +            release_sem (lock->Read);
  +    	}
  +    }
  +    if (lock->WriteCount != 0) {
  +    	while (atomic_add(&lock->WriteCount , -1) > 1){
  +            release_sem (lock->Write);
  +    	}
  +    }
  +    if (lock->LockCount != 0) {
  +    	while (atomic_add(&lock->LockCount , -1) > 1){
  +            release_sem (lock->Lock);
  +    	}
  +    }
  +    
  +    delete_sem(lock->Read);
  +    delete_sem(lock->Write);
  +    delete_sem(lock->Lock);
  +    return APR_SUCCESS;
  +}    
  +
   static apr_status_t _create_lock(apr_lock_t *new)
   {
       int32 stat;
       
  -    if ((stat = create_sem(0, "apr_lock")) < B_NO_ERROR) {
  +    if ((stat = create_sem(0, "APR_Lock")) < B_NO_ERROR) {
           _lock_cleanup(new);
           return stat;
       }
  -    new->ben = 0;
  -    new->sem = stat;
  +    new->LockCount = 0;
  +    new->Lock = stat;
       apr_pool_cleanup_register(new->pool, (void *)new, _lock_cleanup,
                                 apr_pool_cleanup_null);
       return APR_SUCCESS;
   }
   
  +static apr_status_t _create_rw_lock(apr_lock_t *new)
  +{
  +    /* we need to make 3 locks... */
  +    new->ReadCount = 0;
  +    new->WriteCount = 0;
  +    new->LockCount = 0;
  +    new->Read  = create_sem(0, "APR_ReadLock");
  +    new->Write = create_sem(0, "APR_WriteLock");
  +    new->Lock  = create_sem(0, "APR_Lock");
  +    
  +    if (new->Lock < 0 || new->Read < 0 || new->Write < 0) {
  +        _lock_rw_cleanup(new);
  +        return -1;
  +    }
  +
  +    apr_pool_cleanup_register(new->pool, (void *)new, _lock_rw_cleanup,
  +                              apr_pool_cleanup_null);
  +    return APR_SUCCESS;
  +}
  +
   static apr_status_t _lock(apr_lock_t *lock)
   {
       int32 stat;
       
  -	if (atomic_add(&lock->ben, 1) > 0) {
  -		if ((stat = acquire_sem(lock->sem)) < B_NO_ERROR) {
  -		    atomic_add(&lock->ben, -1);
  +	if (atomic_add(&lock->LockCount, 1) > 0) {
  +		if ((stat = acquire_sem(lock->Lock)) < B_NO_ERROR) {
  +		    atomic_add(&lock->LockCount, -1);
   		    return stat;
   		}
   	}
  @@ -107,15 +157,112 @@
   {
       int32 stat;
       
  -	if (atomic_add(&lock->ben, -1) > 1) {
  -        if ((stat = release_sem(lock->sem)) < B_NO_ERROR) {
  -            atomic_add(&lock->ben, 1);
  +	if (atomic_add(&lock->LockCount, -1) > 1) {
  +        if ((stat = release_sem(lock->Lock)) < B_NO_ERROR) {
  +            atomic_add(&lock->LockCount, 1);
               return stat;
           }
       }
       return APR_SUCCESS;
   }
   
  +static apr_status_t _read_lock(apr_lock_t *lock)
  +{
  +    int32 rv = APR_SUCCESS;
  +
  +    if (find_thread(NULL) == lock->writer) {
  +        /* we're the writer - no problem */
  +        lock->Nested++;
  +    } else {
  +        /* we're not the writer */
  +        int32 r = atomic_add(&lock->ReadCount, 1);
  +        if (r < 0) {
  +            /* Oh dear, writer holds lock, wait for sem */
  +            rv = acquire_sem_etc(lock->Read, 1, B_DO_NOT_RESCHEDULE,
  +                                 B_INFINITE_TIMEOUT);
  +        }
  +    }
  +
  +    return rv;
  +}
  +
  +static apr_status_t _write_lock(apr_lock_t *lock)
  +{
  +    int rv = APR_SUCCESS;
  +
  +    if (find_thread(NULL) == lock->writer) {
  +        lock->Nested++;
  +    } else {
  +        /* we're not the writer... */
  +        if (atomic_add(&lock->LockCount, 1) >= 1) {
  +            /* we're locked - acquire the sem */
  +            rv = acquire_sem_etc(lock->Lock, 1, B_DO_NOT_RESCHEDULE,
  +                                 B_INFINITE_TIMEOUT);
  +        }
  +        if (rv == APR_SUCCESS) {
  +            /* decrement the ReadCount to a large -ve number so that
  +             * we block on new readers...
  +             */
  +            int32 readers = atomic_add(&lock->ReadCount, -BIG_NUM);
  +            if (readers > 0) {
  +                /* readers are holding the lock */
  +                rv = acquire_sem_etc(lock->Write, readers, B_DO_NOT_RESCHEDULE,
  +                                     B_INFINITE_TIMEOUT);
  +            }
  +            if (rv == APR_SUCCESS)
  +                lock->writer = find_thread(NULL);
  +        }
  +    }
  +    
  +    return rv;
  +}
  +
  +
  +static apr_status_t _read_unlock(apr_lock_t *lock)
  +{
  +    apr_status_t rv = APR_SUCCESS;
  +    
  +    /* we know we hold the lock, so don't check it :) */
  +    if (find_thread(NULL) == lock->writer) {
  +        /* we're recursively locked */
  +        lock->Nested--;
  +        return APR_SUCCESS;
  +    }
  +    /* OK so we need to release the sem if we have it :) */
  +    if (atomic_add(&lock->ReadCount, -1) < 0) {
  +        /* we have a writer waiting for the lock, so release it */
  +        rv = release_sem_etc(lock->Write, 1, B_DO_NOT_RESCHEDULE);
  +    }
  +
  +    return rv;
  +}
  +
  +static apr_status_t _write_unlock(apr_lock_t *lock)
  +{
  +    apr_status_t rv = APR_SUCCESS;
  +    int32 readers;
  +    
  +    /* we know we hold the lock, so don't check it :) */
  +    if (lock->Nested > 1) {
  +        /* we're recursively locked */
  +        lock->Nested--;
  +        return APR_SUCCESS;
  +    }
  +    /* OK so we need to release the sem if we have it :) */
  +    readers = atomic_add(&lock->ReadCount, BIG_NUM) + BIG_NUM;
  +    if (readers > 0) {
  +        rv = release_sem_etc(lock->Read, readers, B_DO_NOT_RESCHEDULE);
  +    }
  +    if (rv == APR_SUCCESS) {
  +        lock->writer = -1;
  +        if (atomic_add(&lock->LockCount, -1) > 1) {
  +            rv = release_sem_etc(lock->Lock, 1, B_DO_NOT_RESCHEDULE);
  +        }
  +    }
  +    
  +    return rv;
  +}
  +
   static apr_status_t _destroy_lock(apr_lock_t *lock)
   {
       apr_status_t stat;
  @@ -131,12 +278,8 @@
                              apr_pool_t *pool)
   {
       apr_lock_t *new;
  -    apr_status_t stat;
  +    apr_status_t stat = APR_SUCCESS;
     
  -    /* FIXME: Remove when read write locks implemented. */ 
  -    if (type == APR_READWRITE)
  -        return APR_ENOTIMPL; 
  -
       new = (apr_lock_t *)apr_pcalloc(pool, sizeof(apr_lock_t));
       if (new == NULL){
           return APR_ENOMEM;
  @@ -146,7 +289,13 @@
       new->type  = type;
       new->scope = scope;
   
  -    if ((stat = _create_lock(new)) != APR_SUCCESS)
  +    if (type == APR_MUTEX) {
  +        stat = _create_lock(new);
  +    } else if (type == APR_READWRITE) {
  +        stat = _create_rw_lock(new);
  +    }
  +            
  +    if (stat != APR_SUCCESS)
           return stat;
   
       (*lock) = new;
  @@ -189,11 +338,12 @@
           switch (e)
           {
           case APR_READER:
  +            _read_lock(lock);
               break;
           case APR_WRITER:
  +            _write_lock(lock);
               break;
           }
  -        return APR_ENOTIMPL;
       }
   
       return APR_SUCCESS;
  @@ -201,7 +351,7 @@
   
   apr_status_t apr_lock_release(apr_lock_t *lock)
   {
  -    apr_status_t stat;
  +    apr_status_t stat = APR_SUCCESS;
   
       if (lock->owner_ref > 0 && lock->owner == apr_os_thread_current()) {
           lock->owner_ref--;
  @@ -212,13 +362,27 @@
       switch (lock->type)
       {
       case APR_MUTEX:
  -        if ((stat = _unlock(lock)) != APR_SUCCESS)
  -            return stat;
  +        stat = _unlock(lock);
           break;
       case APR_READWRITE:
  -        return APR_ENOTIMPL;
  +        {
  +            thread_id me = find_thread(NULL);
  +            if (me == lock->writer)
  +                stat = _write_unlock(lock);
  +            else
  +                stat = _read_unlock(lock);
  +        }
  +        /* if we don't hold the read or write lock then why are
  +         * we calling release???
  +         *
  +         * Just return success.
  +         */
  +        break;
       }
   
  +    if (stat != APR_SUCCESS)
  +        return stat;
  +    
       lock->owner = -1;
       lock->owner_ref = 0;
   
  @@ -261,8 +425,8 @@
   
   apr_status_t apr_os_lock_get(apr_os_lock_t *oslock, apr_lock_t *lock)
   {
  -    oslock->sem = lock->sem;
  -    oslock->ben = lock->ben;
  +    oslock->sem = lock->Lock;
  +    oslock->ben = lock->LockCount;
       return APR_SUCCESS;
   }
   
  @@ -276,8 +440,8 @@
           (*lock) = (apr_lock_t *)apr_pcalloc(pool, sizeof(apr_lock_t));
           (*lock)->pool = pool;
       }
  -    (*lock)->sem = thelock->sem;
  -    (*lock)->ben = thelock->ben;
  +    (*lock)->Lock = thelock->sem;
  +    (*lock)->LockCount = thelock->ben;
   
       return APR_SUCCESS;
   }