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

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