Kernel - Added a Read-Write lock implimentation (untested)
[tpg/acess2.git] / KernelLand / Kernel / rwlock.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * rwlock.c
6  * - Reader-Writer Lockes
7  */
8 #include <acess.h>
9 #include <threads_int.h>
10 #include <rwlock.h>
11
12 // === PROTOTYPES ===
13 //
14 // Acquire as a reader (see rwlock.h for documentation)
15 //
16 int RWLock_AcquireRead(tRWLock *Lock)
17 {
18         tThread *us;
19         // Get protector
20         SHORTLOCK( &Lock->Protector );
21         
22         // Check if the lock is already held by a writer
23         if( Lock->Owner )
24         {
25                 SHORTLOCK( &glThreadListLock );
26                 
27                 // - Remove from active list
28                 us = Threads_RemActive();
29                 us->Next = NULL;
30                 // - Mark as sleeping
31                 us->Status = THREAD_STAT_RWLOCKSLEEP;
32                 us->WaitPointer = Lock;
33                 
34                 // - Add to waiting
35                 if(Lock->ReaderWaiting)
36                         Lock->ReaderWaitingLast->Next = us;
37                 else
38                         Lock->ReaderWaiting = us;
39                 Lock->ReaderWaitingLast = us;
40                 
41                 #if DEBUG_TRACE_STATE
42                 Log("%p (%i %s) waiting on rwlock %p",
43                         us, us->TID, us->ThreadName, Lock);
44                 #endif
45                 
46                 SHORTREL( &glThreadListLock );
47                 SHORTREL( &Lock->Protector );
48                 while(us->Status == THREAD_STAT_RWLOCKSLEEP)    Threads_Yield();
49                 // We're only woken when we get the lock
50                 // TODO: Handle when this isn't the case
51                 us->WaitPointer = NULL;
52         }
53         // Ooh, no problems then!
54         else
55         {
56                 Lock->Level++;
57                 SHORTREL( & Lock->Protector );
58         }
59         
60         return 0;
61 }
62
63 int RWLock_AcquireWrite(tRWLock *Lock)
64 {
65         tThread *us;
66         
67         SHORTLOCK(&Lock->Protector);
68         if( Lock->Owner || Lock->Level != 0 )
69         {
70                 SHORTLOCK(&glThreadListLock);
71                 
72                 us = Threads_RemActive();
73                 us->Next = NULL;
74                 us->Status = THREAD_STAT_RWLOCKSLEEP;
75                 us->WaitPointer = Lock;
76                 
77                 if( Lock->WriterWaiting )
78                         Lock->WriterWaitingLast->Next = us;
79                 else
80                         Lock->WriterWaiting = us;
81                 Lock->WriterWaitingLast = us;
82                 
83                 SHORTREL( &glThreadListLock );
84                 SHORTREL( &Lock->Protector );
85                 
86                 while(us->Status == THREAD_STAT_RWLOCKSLEEP)    Threads_Yield();
87                 us->WaitPointer = NULL;
88         }
89         else
90         {
91                 // Nothing else is using the lock, nice :)
92                 Lock->Owner = Proc_GetCurThread();
93                 SHORTREL(&Lock->Protector);
94         }
95         return 0;
96 }
97
98 // Release a mutex
99 void RWLock_Release(tRWLock *Lock)
100 {
101         SHORTLOCK( &Lock->Protector );
102
103         if( Lock->Owner == Proc_GetCurThread() )
104                 Lock->Level --;
105         
106         // Writers first
107         if( Lock->WriterWaiting )
108         {
109                 Lock->Owner = Lock->WriterWaiting;      // Set owner
110                 Lock->WriterWaiting = Lock->WriterWaiting->Next;        // Next!
111                 
112                 // Wake new owner
113                 if( Lock->Owner->Status != THREAD_STAT_ACTIVE )
114                         Threads_AddActive(Lock->Owner);
115         }
116         else
117         {
118                 Lock->Owner = NULL;
119                 
120                 while( Lock->ReaderWaiting ) {
121                         Lock->Level ++;
122                         Threads_AddActive(Lock->ReaderWaiting);
123                         Lock->ReaderWaiting = Lock->ReaderWaiting->Next;
124                 }
125         }
126         SHORTREL( &Lock->Protector );
127 }
128
129 // === EXPORTS ===
130 EXPORT(RWLock_AcquireRead);
131 EXPORT(RWLock_AcquireWrite);
132 EXPORT(RWLock_Release);

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