Kernel - Added a Read-Write lock implimentation (untested)
authorJohn Hodge <[email protected]>
Sat, 14 Jul 2012 05:06:10 +0000 (13:06 +0800)
committerJohn Hodge <[email protected]>
Sat, 14 Jul 2012 05:06:10 +0000 (13:06 +0800)
KernelLand/Kernel/include/rwlock.h [new file with mode: 0644]
KernelLand/Kernel/rwlock.c [new file with mode: 0644]

diff --git a/KernelLand/Kernel/include/rwlock.h b/KernelLand/Kernel/include/rwlock.h
new file mode 100644 (file)
index 0000000..a6f46b5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Acess2 Kernel
+ * 
+ * rwmutex.c
+ * - Reader-Writer Mutex (Multiple Readers, One Writer)
+ */
+#ifndef _RWLOCK_H
+#define _RWLOCK_H
+
+#include <acess.h>
+
+typedef struct sRWLock tRWLock;
+
+struct sRWLock
+{
+       tShortSpinlock  Protector;      //!< Protector for the lock strucure
+       const char      *Name;  //!< Human-readable name
+        int    Level;  // Number of readers active
+       struct sThread  *volatile Owner;        //!< Owner of the lock (set upon getting the lock)
+       struct sThread  *ReaderWaiting;         //!< Waiting threads (readers)
+       struct sThread  *ReaderWaitingLast;     //!< Waiting threads
+       
+       struct sThread  *WriterWaiting;         //!< Waiting threads (writers)
+       struct sThread  *WriterWaitingLast;     //!< Waiting threads
+};
+
+/**
+ * \brief Acquire a heavy mutex
+ * \param Mutex        Mutex to acquire
+ * \return zero on success, -1 if terminated
+ * 
+ * This type of mutex checks if the mutex is avaliable, and acquires it
+ * if it is. Otherwise, the current thread is added to the mutex's wait
+ * queue and the thread suspends. When the holder of the mutex completes,
+ * the oldest thread (top thread) on the queue is given the lock and
+ * restarted.
+ */
+extern int     RWLock_AcquireRead(tRWLock *Lock);
+
+extern int     RWLock_AcquireWrite(tRWLock *LOck);
+
+/**
+ * \brief Release a held mutex
+ * \param Mutex        Mutex to release
+ * \note Releasing a non-held mutex has no effect
+ */
+extern void    RWLock_Release(tRWLock *Lock);
+
+#endif
diff --git a/KernelLand/Kernel/rwlock.c b/KernelLand/Kernel/rwlock.c
new file mode 100644 (file)
index 0000000..6706bb2
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * rwlock.c
+ * - Reader-Writer Lockes
+ */
+#include <acess.h>
+#include <threads_int.h>
+#include <rwlock.h>
+
+// === PROTOTYPES ===
+//
+// Acquire as a reader (see rwlock.h for documentation)
+//
+int RWLock_AcquireRead(tRWLock *Lock)
+{
+       tThread *us;
+       // Get protector
+       SHORTLOCK( &Lock->Protector );
+       
+       // Check if the lock is already held by a writer
+       if( Lock->Owner )
+       {
+               SHORTLOCK( &glThreadListLock );
+               
+               // - Remove from active list
+               us = Threads_RemActive();
+               us->Next = NULL;
+               // - Mark as sleeping
+               us->Status = THREAD_STAT_RWLOCKSLEEP;
+               us->WaitPointer = Lock;
+               
+               // - Add to waiting
+               if(Lock->ReaderWaiting)
+                       Lock->ReaderWaitingLast->Next = us;
+               else
+                       Lock->ReaderWaiting = us;
+               Lock->ReaderWaitingLast = us;
+               
+               #if DEBUG_TRACE_STATE
+               Log("%p (%i %s) waiting on rwlock %p",
+                       us, us->TID, us->ThreadName, Lock);
+               #endif
+               
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &Lock->Protector );
+               while(us->Status == THREAD_STAT_RWLOCKSLEEP)    Threads_Yield();
+               // We're only woken when we get the lock
+               // TODO: Handle when this isn't the case
+               us->WaitPointer = NULL;
+       }
+       // Ooh, no problems then!
+       else
+       {
+               Lock->Level++;
+               SHORTREL( & Lock->Protector );
+       }
+       
+       return 0;
+}
+
+int RWLock_AcquireWrite(tRWLock *Lock)
+{
+       tThread *us;
+       
+       SHORTLOCK(&Lock->Protector);
+       if( Lock->Owner || Lock->Level != 0 )
+       {
+               SHORTLOCK(&glThreadListLock);
+               
+               us = Threads_RemActive();
+               us->Next = NULL;
+               us->Status = THREAD_STAT_RWLOCKSLEEP;
+               us->WaitPointer = Lock;
+               
+               if( Lock->WriterWaiting )
+                       Lock->WriterWaitingLast->Next = us;
+               else
+                       Lock->WriterWaiting = us;
+               Lock->WriterWaitingLast = us;
+               
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &Lock->Protector );
+               
+               while(us->Status == THREAD_STAT_RWLOCKSLEEP)    Threads_Yield();
+               us->WaitPointer = NULL;
+       }
+       else
+       {
+               // Nothing else is using the lock, nice :)
+               Lock->Owner = Proc_GetCurThread();
+               SHORTREL(&Lock->Protector);
+       }
+       return 0;
+}
+
+// Release a mutex
+void RWLock_Release(tRWLock *Lock)
+{
+       SHORTLOCK( &Lock->Protector );
+
+       if( Lock->Owner == Proc_GetCurThread() )
+               Lock->Level --;
+       
+       // Writers first
+       if( Lock->WriterWaiting )
+       {
+               Lock->Owner = Lock->WriterWaiting;      // Set owner
+               Lock->WriterWaiting = Lock->WriterWaiting->Next;        // Next!
+               
+               // Wake new owner
+               if( Lock->Owner->Status != THREAD_STAT_ACTIVE )
+                       Threads_AddActive(Lock->Owner);
+       }
+       else
+       {
+               Lock->Owner = NULL;
+               
+               while( Lock->ReaderWaiting ) {
+                       Lock->Level ++;
+                       Threads_AddActive(Lock->ReaderWaiting);
+                       Lock->ReaderWaiting = Lock->ReaderWaiting->Next;
+               }
+       }
+       SHORTREL( &Lock->Protector );
+}
+
+// === EXPORTS ===
+EXPORT(RWLock_AcquireRead);
+EXPORT(RWLock_AcquireWrite);
+EXPORT(RWLock_Release);

UCC git Repository :: git.ucc.asn.au