public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "Jeff V. Merkey" <jmerkey@wolfmountaingroup.com>
To: Joshua Hudson <joshudson@gmail.com>
Cc: linux-kernel@vger.kernel.org
Subject: Re: readers-writers mutex
Date: Wed, 05 Apr 2006 19:15:17 -0600	[thread overview]
Message-ID: <44346BA5.7060400@wolfmountaingroup.com> (raw)
In-Reply-To: <bda6d13a0604051521o229de77dvb38992d6427a450c@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2468 bytes --]

Joshua Hudson wrote:

>Since we are moving from semaphores to mutex, there should be a
>mutex_rw. I had a try
>at creating one (might as well convert from sem_rw). I'll bet somebody
>here can do a
>lot better, but this will do if need be.
>
>--- linux-2.6.16.1-stock/include/linux/mutex_rw.h       1969-12-31
>16:00:00.000000000 -0800
>+++ linux-2.6.16.1-nvl/include/linux/mutex_rw.h 2006-04-04
>18:11:56.000000000 -0700
>@@ -0,0 +1,60 @@
>+/* Linux RW mutex
>+ * This file: GNU GPL v2 or later, Joshua Hudson <joshudson@gmail.com>
>+ *
>+ * Somebody else can make this fast. I just made this work.
>+ *
>+ * DANGER! Change of this file will break module binaries if any
>+ *  rw mutex is shared between main kernel and modules or between
>+ *  modules with a different version.
>+ */
>+
>+#ifndef __KERNEL_MUTEX_RW
>+#define __KERNEL_MUTEX_RW
>+#ifdef __KERNEL__
>+
>+#include <linux/mutex.h>
>+
>+struct rw_mutex {
>+       struct mutex r_mutex;
>+       struct mutex w_mutex;
>+       unsigned n_readers;
>+};
>+
>+static inline void rw_mutex_init(struct rw_mutex *rw)
>+{
>+       mutex_init(&rw->r_mutex);
>+       mutex_init(&rw->w_mutex);
>+       rw->n_readers = 0;
>+}
>+
>+static inline void rw_mutex_destroy(struct rw_mutex *rw)
>+{
>+       mutex_destroy(&rw->r_mutex);
>+       mutex_destroy(&rw->w_mutex);
>+}
>+
>+static inline void mutex_lock_w(struct rw_mutex *rw)
>+{
>+       mutex_lock(&rw->w_mutex);
>+}
>+
>+static inline void mutex_unlock_w(struct rw_mutex *rw)
>+{
>+       mutex_unlock(&rw->w_mutex);
>+}
>+
>+static inline void mutex_lock_r(struct rw_mutex *rw)
>+{
>+       mutex_lock(&rw->r_mutex);
>+       if (++rw->n_readers == 1)
>+               mutex_lock(&rw->w_mutex);
>+       mutex_unlock(&rw->r_mutex);
>+}
>+
>+static inline void mutex_unlock_r(struct rw_mutex *rw)
>+{
>+       mutex_lock(&rw->r_mutex);
>+       if (--rw->n_readers == 0)
>+               mutex_unlock(&rw->w_mutex);
>+       mutex_unlock(&rw->r_mutex);
>+}
>+
>+#endif
>+#endif
>-
>To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>Please read the FAQ at  http://www.tux.org/lkml/
>
>  
>
Race conditions here.

Try this code. These have been tested and I have been using the code for 
couple of years in another OS (which is just about done now and is in 
alpha and beta and little more SMP friendly).

Jeff





[-- Attachment #2: rwlock.c --]
[-- Type: text/x-csrc, Size: 22909 bytes --]



/***************************************************************************
*
*   Copyright (c) 2005, 2006 Cherokee Nation. All Rights Reserved. 
*
*   This Program is released under GPLv3
*
*   AUTHOR   :  Jeff V. Merkey
*   FILE     :  RWLOCK.C
*   DESCRIP  :  Multi-Processing Reader/Writer Locks Gadugi v7
*   DATE     :  October 23, 2004
*
***************************************************************************/

#include "stdarg.h"
#include "stdio.h"
#include "stdlib.h"
#include "ctype.h"
#include "string.h"
#include "kernel.h"
#include "keyboard.h"
#include "screen.h"
#include "types.h"
#include "emit.h"
#include "dos.h"
#include "tss.h"
#include "os.h"
#include "mps.h"
#include "hal.h"
#include "timer.h"
#include "peexe.h"
#include "malloc.h"
#include "free.h"
#include "event.h"

#define  WRITER_OWNED   -10
#define  READER_OWNED   -11
#define  UNOWNED        -12

rwlock_t *rwlock_init(rwlock_t *rwlock);
rwlock_t *rwlock_alloc(void);
LONG rwlock_free(rwlock_t *rwlock);
LONG rwlock_read_lock(rwlock_t *rwlock);
LONG rwlock_write_lock(rwlock_t *rwlock);
LONG rwlock_read_try_lock(rwlock_t *rwlock);
LONG rwlock_write_try_lock(rwlock_t *rwlock);
LONG rwlock_unlock(rwlock_t *rwlock);
LONG rwlock_reader_to_writer(rwlock_t *rwlock);
LONG rwlock_reader_to_writer_unordered(rwlock_t *rwlock);
LONG rwlock_writer_to_reader(rwlock_t *rwlock);
LONG rwlock_release(rwlock_t *rwlock);
PROCESS *get_rwlock_process(rwlock_t *rwlock);
void put_rwlock_process(rwlock_t *rwlock, PROCESS *p);

rwlock_t *rwlock_init(rwlock_t *rwlock)
{

   if (rwlock && !rwlock->signature)
   {
      SetData((LONG *) rwlock, 0, sizeof(rwlock_t));
      rwlock->signature = LRWLOCK_SIGNATURE;
      rwlock->flags = UNOWNED;
      return (rwlock_t *) rwlock;
   }
   return 0;

}

rwlock_t *rwlock_alloc(void)
{

   register rwlock_t *rwlock;

   rwlock = kmalloc(sizeof(rwlock_t));
   if (rwlock)
   {
      SetData((LONG *) rwlock, 0, sizeof(rwlock_t));
      rwlock->signature = RWLOCK_SIGNATURE;
      rwlock->flags = UNOWNED;
      return (rwlock_t *) rwlock;
   }
   return 0;

}

LONG rwlock_free(rwlock_t *rwlock)
{
    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       if (!rwlock_release(rwlock))
       {
	  if (rwlock->signature == RWLOCK_SIGNATURE)
	     kfree(rwlock);
	  else
	     rwlock->signature = 0;
	  return 0;
       }
       return -2;
    }
    return -1;

}

#if RWLOCK_TRACE

BYTE *get_RW_TYPE(LONG p)
{
     switch (p)
     {
	case RREAD_LOCK:
	   return "READ_LOCK";

	case RREAD_UNLOCK:
	   return "READ_UNLOCK";

	case WWRITE_LOCK:
	   return "WRITE_LOCK";

	case WWRITE_UNLOCK:
	   return "WRITE_UNLOCK";

	default:
	   return "????";
     }

}

BYTE *get_RW_OP(LONG p)
{
    switch (p)
    {
       case READER_LOCK:
	  return "READER_LOCK  ";

       case READER_UNLOCK:
	  return "READER_UNLOCK";

       case READER_SLEEP:
	  return "READER_SLEEP ";

       case READER_WAKE:
	  return "READER_WAKE  ";

       case WRITER_LOCK:
	  return "WRITER_LOCK  ";

       case WRITER_UNLOCK:
	  return "WRITER_UNLOCK";

       case WRITER_SLEEP:
	  return "WRITER_SLEEP ";

       case WRITER_WAKE:
	  return "WRITER_WAKE  ";

       default:
	  return "????         ";
    }
}

void RW_DISPLAY(SCREEN *screen, rwlock_t *rwlock)
{
     register LONG i;

     SetPauseMode(screen, screen->nLines - 5);

     printfScreen(screen, "RWIndex %d\n");
     for (i=0; i < 256; i++)
     {
	printfScreen(screen, "process-%08X time-%08X target-%08X s-%s t-%s\n",
		      rwlock->RWProcess[i],
		      rwlock->RWTime[i],
		      rwlock->RWTarget[i],
		      get_RW_OP(rwlock->RWOp[i]),
		      get_RW_TYPE(rwlock->RWType[i]));
     }

     ClearPauseMode(screen);

     return;

}

void RW_TRACE(rwlock_t *rwlock, LONG event, LONG target, LONG type)
{
     LONG base, counter;

     GetSystemDTSC(&base, &counter);
     rwlock->RWProcess[rwlock->RWIndex & 0xFF] = (LONG) get_running_process();
     rwlock->RWOp[rwlock->RWIndex & 0xFF] = event;
     rwlock->RWTarget[rwlock->RWIndex & 0xFF] = target;
     rwlock->RWType[rwlock->RWIndex & 0xFF] = type;
     rwlock->RWTime[rwlock->RWIndex & 0xFF] = (LONG) base;
     rwlock->RWIndex++;

}

#endif

LONG rwlock_read_lock(rwlock_t *rwlock)
{
    register PROCESS *p = get_running_process();
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);
       p->syncFlag = 0;
       switch (rwlock->flags)
       {
	  case WRITER_OWNED:
#if RWLOCK_TRACE
	     RW_TRACE(rwlock, READER_SLEEP, (LONG) p, RREAD_LOCK);
#endif
	     spin_lock(&p->threadMutex);    // lock current thread
	     put_rwlock_process(rwlock, p);
	     p->stackPointer = 0;
	     p->threadState = PS_SLEEP;
	     p->syncObject = rwlock;
	     p->syncState = PROCESS_READER_BLOCKED_SYNC;
	     spin_unlock(&rwlock->mutex);
	     thread_switch();               // context switch will unlock thread
	     cli();
	     set_flags(flags);
	     return p->syncFlag;

	  case READER_OWNED:
	     if (rwlock->writers)
	     {
#if RWLOCK_TRACE
		RW_TRACE(rwlock, READER_SLEEP, (LONG) p, RREAD_LOCK);
#endif
		spin_lock(&p->threadMutex);    // lock current thread
		put_rwlock_process(rwlock, p);
		p->stackPointer = 0;
		p->threadState = PS_SLEEP;
		p->syncObject = rwlock;
		p->syncState = PROCESS_READER_BLOCKED_SYNC;
		spin_unlock(&rwlock->mutex);
		thread_switch();               // context switch will unlock thread
		cli();
		set_flags(flags);
		return p->syncFlag;
	     }

#if RWLOCK_TRACE
	     RW_TRACE(rwlock, READER_LOCK, 0, RREAD_LOCK);
#endif
	     rwlock->flags = (LONG) READER_OWNED;
	     rwlock->readers++;          // set reader count
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return p->syncFlag;

	  case UNOWNED:
#if RWLOCK_TRACE
	     RW_TRACE(rwlock, READER_LOCK, 0, RREAD_LOCK);
#endif
	     rwlock->flags = (LONG) READER_OWNED;
	     rwlock->readers++;          // set reader count
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return p->syncFlag;

	  default:
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;
       }
    }
    return -1;

}

LONG rwlock_write_lock(rwlock_t *rwlock)
{
    register PROCESS *p = get_running_process();
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);
       p->syncFlag = 0;
       switch (rwlock->flags)
       {
	  case READER_OWNED:
	  case WRITER_OWNED:
#if RWLOCK_TRACE
	     RW_TRACE(rwlock, WRITER_SLEEP, (LONG) p, WWRITE_LOCK);
#endif
	     spin_lock(&p->threadMutex);    // lock current thread
	     put_rwlock_process(rwlock, p);
	     rwlock->writers++;
	     p->stackPointer = 0;
	     p->threadState = PS_SLEEP;
	     p->syncObject = rwlock;
	     p->syncState = PROCESS_WRITER_BLOCKED_SYNC;
	     spin_unlock(&rwlock->mutex);
	     thread_switch();               // context switch will unlock thread
	     cli();
	     set_flags(flags);
	     return p->syncFlag;

	  case UNOWNED:
#if RWLOCK_TRACE
	     RW_TRACE(rwlock, WRITER_LOCK, 0, WWRITE_LOCK);
#endif
	     rwlock->flags = (LONG) WRITER_OWNED;
	     rwlock->owner = (LONG) p;
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return p->syncFlag;

	  default:
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;
       }
    }
    return -1;

}

LONG rwlock_read_try_lock(rwlock_t *rwlock)
{
    register PROCESS *p = get_running_process();
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);
       p->syncFlag = 0;
       switch (rwlock->flags)
       {
	  case WRITER_OWNED:
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return 1;

	  case READER_OWNED:
	     if (rwlock->writers)
	     {
		spin_unlock(&rwlock->mutex);
		set_flags(flags);
		return 1;
	     }
#if RWLOCK_TRACE
	     RW_TRACE(rwlock, READER_LOCK, 0, RREAD_TRY_LOCK);
#endif
	     rwlock->flags = (LONG) READER_OWNED;
	     rwlock->readers++;          // set reader count
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return p->syncFlag;

	  case UNOWNED:
#if RWLOCK_TRACE
	     RW_TRACE(rwlock, READER_LOCK, 0, RREAD_TRY_LOCK);
#endif
	     rwlock->flags = (LONG) READER_OWNED;
	     rwlock->readers++;          // set reader count
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return p->syncFlag;

	  default:
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;
       }
    }
    return -1;

}

LONG rwlock_write_try_lock(rwlock_t *rwlock)
{
    register PROCESS *p = get_running_process();
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);
       p->syncFlag = 0;
       switch (rwlock->flags)
       {
	  case READER_OWNED:
	  case WRITER_OWNED:
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return 1;

	  case UNOWNED:
#if RWLOCK_TRACE
	     RW_TRACE(rwlock, WRITER_LOCK, 0, WWRITE_TRY_LOCK);
#endif
	     rwlock->flags = (LONG) WRITER_OWNED;
	     rwlock->owner = (LONG) p;
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return p->syncFlag;

	  default:
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;
       }
    }
    return -1;

}

LONG rwlock_read_unlock(rwlock_t *rwlock)
{
    register PROCESS *p;
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);
       switch (rwlock->flags)
       {
	  case WRITER_OWNED:
	     panic("rwlock_read_unlock called with writer owning rwlock");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;

	  case READER_OWNED:
	     if (rwlock->readers)
		rwlock->readers--;

#if RWLOCK_TRACE
	     RW_TRACE(rwlock, READER_UNLOCK, 0, RREAD_UNLOCK);
#endif
	     if (!rwlock->readers)
	     {
		rwlock->flags = UNOWNED;
		if (rwlock->head)
		{
		   p = rwlock->head;
		   if (p->syncState != PROCESS_WRITER_BLOCKED_SYNC)
		   {
		      panic("rwlock_read_unlock called with sleeping READER");
		      spin_unlock(&rwlock->mutex);
		      set_flags(flags);
		      return -1;
		   }

		   p = get_rwlock_process(rwlock);
		   rwlock->writers--;
		   spin_lock(&p->threadMutex);     // lock thread
		   if (p->threadState == PS_SLEEP)
		   {
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, RREAD_UNLOCK);
#endif
		      p->threadState = PS_ACTIVE;
		      p->syncObject = 0;
		      p->syncState = 0;
		      p->syncFlag = 0;
		      (!p->processorBinding)
		      ? put_dispatch(p)
		      : put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_LOCK, 0, RREAD_UNLOCK);
#endif
		      rwlock->flags = WRITER_OWNED;
		      rwlock->owner = (LONG) p;
		   }
		   spin_unlock(&p->threadMutex);   // unlock thread
		}
	     }
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return 0;

	  case UNOWNED:
	  default:
	     panic("rwlock_read_unlock called in inconsistent state");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;
       }
    }
    return -1;
}

LONG rwlock_write_unlock(rwlock_t *rwlock)
{
    register PROCESS *p, *curr;
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);

       curr = get_running_process();
       if (rwlock->owner != (LONG) curr)
       {
	  panic("rwlock_write_unlock called by process other than owner");
	  spin_unlock(&rwlock->mutex);
	  set_flags(flags);
	  return -1;
       }

       switch (rwlock->flags)
       {
	  case WRITER_OWNED:
#if RWLOCK_TRACE
	     RW_TRACE(rwlock, WRITER_UNLOCK, 0, WWRITE_UNLOCK);
#endif
	     rwlock->owner = 0;
	     rwlock->flags = UNOWNED;
	     if (rwlock->head)
	     {
		p = rwlock->head;
		if (p->syncState == PROCESS_WRITER_BLOCKED_SYNC)
		{
		   p = get_rwlock_process(rwlock);
		   rwlock->writers--;
		   spin_lock(&p->threadMutex);     // lock thread
		   if (p->threadState == PS_SLEEP)
		   {
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, WWRITE_UNLOCK);
#endif
		      p->threadState = PS_ACTIVE;
		      p->syncObject = 0;
		      p->syncState = 0;
		      p->syncFlag = 0;
		      (!p->processorBinding)
		      ? put_dispatch(p)
		      : put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_LOCK, 0, WWRITE_UNLOCK);
#endif
		      rwlock->flags = WRITER_OWNED;
		      rwlock->owner = (LONG) p;
		   }
		   spin_unlock(&p->threadMutex);   // unlock thread
		   spin_unlock(&rwlock->mutex);
		   set_flags(flags);
		   return 0;
		}

		while (rwlock->head)
		{
		   p = rwlock->head;
		   if (p->syncState == PROCESS_WRITER_BLOCKED_SYNC)
		      break;

		   p = get_rwlock_process(rwlock);
		   spin_lock(&p->threadMutex);     // lock thread
		   if (p->threadState == PS_SLEEP)
		   {
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, READER_WAKE, (LONG) p, WWRITE_UNLOCK);
#endif
		      p->threadState = PS_ACTIVE;
		      p->syncObject = 0;
		      p->syncState = 0;
		      p->syncFlag = 0;
		      (!p->processorBinding)
		      ? put_dispatch(p)
		      : put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, READER_LOCK, 0, WWRITE_UNLOCK);
#endif
		      rwlock->flags = READER_OWNED;
		      rwlock->readers++;
		      rwlock->owner = 0;                           		}
		   }
		   spin_unlock(&p->threadMutex);   // unlock thread

	     }
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return 0;

	  case READER_OWNED:
	     panic("rwlock_write_unlock called with reader owning rwlock");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;

	  case UNOWNED:
	  default:
	     panic("rwlock_write_unlock called in inconsistent state");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;
       }
    }
    return -1;
}


LONG rwlock_reader_to_writer(rwlock_t *rwlock)
{
    register PROCESS *p;
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);
       switch (rwlock->flags)
       {
	  case WRITER_OWNED:
	     panic("rwlock_reader_to_writer called with writer owning rwlock");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;

	  case READER_OWNED:
	     if (rwlock->readers)
		rwlock->readers--;

#if RWLOCK_TRACE
	     RW_TRACE(rwlock, READER_UNLOCK, 0, RREAD_UNLOCK);
#endif
	     if (!rwlock->readers)
	     {
		rwlock->flags = UNOWNED;
		if (rwlock->head)
		{
		   p = rwlock->head;
		   if (p->syncState != PROCESS_WRITER_BLOCKED_SYNC)
		   {
		      panic("rwlock_read_unlock called with sleeping READER");
		      spin_unlock(&rwlock->mutex);
		      set_flags(flags);
		      return -1;
		   }

		   p = get_rwlock_process(rwlock);
		   rwlock->writers--;
		   spin_lock(&p->threadMutex);     // lock thread
		   if (p->threadState == PS_SLEEP)
		   {
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, RREAD_UNLOCK);
#endif
		      p->threadState = PS_ACTIVE;
		      p->syncObject = 0;
		      p->syncState = 0;
		      p->syncFlag = 0;
		      (!p->processorBinding)
		      ? put_dispatch(p)
		      : put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_LOCK, 0, RREAD_UNLOCK);
#endif
		      rwlock->flags = WRITER_OWNED;
		      rwlock->owner = (LONG) p;
		   }
		   spin_unlock(&p->threadMutex);   // unlock thread
		}
	     }
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return 0;

	  case UNOWNED:
	  default:
	     panic("rwlock_reader_to_writer called in inconsistent state");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;
       }
    }
    return -1;
}

LONG rwlock_reader_to_writer_unordered(rwlock_t *rwlock)
{
    register PROCESS *p;
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);
       switch (rwlock->flags)
       {
	  case WRITER_OWNED:
	     panic("rwlock_reader_to_writer_unordered called with writer owning rwlock");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;

	  case READER_OWNED:
	     if (rwlock->readers)
		rwlock->readers--;

#if RWLOCK_TRACE
	     RW_TRACE(rwlock, READER_UNLOCK, 0, RREAD_UNLOCK);
#endif
	     if (!rwlock->readers)
	     {
		rwlock->flags = UNOWNED;
		if (rwlock->head)
		{
		   p = rwlock->head;
		   if (p->syncState != PROCESS_WRITER_BLOCKED_SYNC)
		   {
		      panic("rwlock_read_unlock called with sleeping READER");
		      spin_unlock(&rwlock->mutex);
		      set_flags(flags);
		      return -1;
		   }

		   p = get_rwlock_process(rwlock);
		   rwlock->writers--;
		   spin_lock(&p->threadMutex);     // lock thread
		   if (p->threadState == PS_SLEEP)
		   {
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, RREAD_UNLOCK);
#endif
		      p->threadState = PS_ACTIVE;
		      p->syncObject = 0;
		      p->syncState = 0;
		      p->syncFlag = 0;
		      (!p->processorBinding)
		      ? put_dispatch(p)
		      : put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_LOCK, 0, RREAD_UNLOCK);
#endif
		      rwlock->flags = WRITER_OWNED;
		      rwlock->owner = (LONG) p;
		   }
		   spin_unlock(&p->threadMutex);   // unlock thread
		}
	     }
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return 0;

	  case UNOWNED:
	  default:
	     panic("rwlock_reader_to_writer_unordered called in inconsistent state");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;
       }
    }
    return -1;
}

LONG rwlock_writer_to_reader(rwlock_t *rwlock)
{
    register PROCESS *p, *curr;
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);

       curr = get_running_process();
       if (rwlock->owner != (LONG) curr)
       {
	  panic("rwlock_writer_to_reader called by process other than owner");
	  spin_unlock(&rwlock->mutex);
	  set_flags(flags);
	  return -1;
       }

       switch (rwlock->flags)
       {
	  case WRITER_OWNED:
#if RWLOCK_TRACE
	     RW_TRACE(rwlock, WRITER_UNLOCK, 0, WWRITE_UNLOCK);
#endif
	     rwlock->owner = 0;
	     rwlock->flags = UNOWNED;
	     if (rwlock->head)
	     {
		p = rwlock->head;
		if (p->syncState == PROCESS_WRITER_BLOCKED_SYNC)
		{
		   p = get_rwlock_process(rwlock);
		   rwlock->writers--;
		   spin_lock(&p->threadMutex);     // lock thread
		   if (p->threadState == PS_SLEEP)
		   {
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_WAKE, (LONG) p, WWRITE_UNLOCK);
#endif
		      p->threadState = PS_ACTIVE;
		      p->syncObject = 0;
		      p->syncState = 0;
		      p->syncFlag = 0;
		      (!p->processorBinding)
		      ? put_dispatch(p)
		      : put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, WRITER_LOCK, 0, WWRITE_UNLOCK);
#endif
		      rwlock->flags = WRITER_OWNED;
		      rwlock->owner = (LONG) p;
		   }
		   spin_unlock(&p->threadMutex);   // unlock thread
		   spin_unlock(&rwlock->mutex);
		   set_flags(flags);
		   return 0;
		}

		while (rwlock->head)
		{
		   p = rwlock->head;
		   if (p->syncState == PROCESS_WRITER_BLOCKED_SYNC)
		      break;

		   p = get_rwlock_process(rwlock);
		   spin_lock(&p->threadMutex);     // lock thread
		   if (p->threadState == PS_SLEEP)
		   {
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, READER_WAKE, (LONG) p, WWRITE_UNLOCK);
#endif
		      p->threadState = PS_ACTIVE;
		      p->syncObject = 0;
		      p->syncState = 0;
		      p->syncFlag = 0;
		      (!p->processorBinding)
		      ? put_dispatch(p)
		      : put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
#if RWLOCK_TRACE
		      RW_TRACE(rwlock, READER_LOCK, 0, WWRITE_UNLOCK);
#endif
		      rwlock->flags = READER_OWNED;
		      rwlock->readers++;
		      rwlock->owner = 0;                           		}
		   }
		   spin_unlock(&p->threadMutex);   // unlock thread

	     }
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return 0;

	  case READER_OWNED:
	     panic("rwlock_writer_to_reader called with reader owning rwlock");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;

	  case UNOWNED:
	  default:
	     panic("rwlock_writer_to_reader called in inconsistent state");
	     spin_unlock(&rwlock->mutex);
	     set_flags(flags);
	     return -1;
       }
    }
    return -1;
}


PROCESS *get_rwlock_process(rwlock_t *rwlock)
{

    register PROCESS *p, *list;

    if (rwlock->head)
    {
       p = rwlock->head;
       list = (PROCESS *) rwlock->head = (void *) p->syncNext;
       if (list)
	  list->syncPrior = NULL;
       else
	  rwlock->tail = NULL;
       return p;
    }
    return 0;

}

void put_rwlock_process(rwlock_t *rwlock, PROCESS *p)
{

    register PROCESS *search, *list;

    search = rwlock->head;
    while (search)
    {
       if (search == p)
	  return;
       search = search->syncNext;
    }

    if (!rwlock->head)
    {
       rwlock->head = rwlock->tail = p;
       p->syncNext = p->syncPrior = 0;
    }
    else
    {
       list = (PROCESS *) rwlock->tail;
       list->syncNext = p;
       p->syncNext = 0;
       p->syncPrior = rwlock->tail;
       rwlock->tail = p;
    }
    return;

}

LONG rwlock_release(rwlock_t *rwlock)
{
    register PROCESS *p, *list;
    register LONG flags;

    if (rwlock->signature == RWLOCK_SIGNATURE ||
	rwlock->signature == LRWLOCK_SIGNATURE)
    {
       flags = get_flags();
       spin_lock(&rwlock->mutex);

       p = rwlock->head;
       while (p)
       {
	  list = p->syncNext;
	  spin_lock(&p->threadMutex);     // lock thread
	  if (p->threadState == PS_SLEEP)
	  {
	     p->threadState = PS_ACTIVE;
	     p->syncObject = 0;
	     p->syncState = 0;
	     p->syncFlag = -2;
	     if (rwlock->waiters)
		rwlock->waiters--;
	     (!p->processorBinding)
	     ? put_dispatch(p)
	     : put_bind_pset(p, (PROCESSOR_SET *)p->processorBinding);
	  }
	  spin_unlock(&p->threadMutex);   // unlock thread
	  p = list;
       }

       rwlock->owner = 0;
       spin_unlock(&rwlock->mutex);
       set_flags(flags);
       return 0;
    }
    return -1;

}

      parent reply	other threads:[~2006-04-06  0:24 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-04-05 22:21 readers-writers mutex Joshua Hudson
2006-04-06  1:06 ` Arjan van de Ven
2006-04-06  1:59   ` Joshua Hudson
2006-04-06  1:15 ` Jeff V. Merkey [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=44346BA5.7060400@wolfmountaingroup.com \
    --to=jmerkey@wolfmountaingroup.com \
    --cc=joshudson@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox