Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


added new copyright and license
[palacios.git] / palacios / src / geekos / synch.c
1 /*
2  * Synchronization primitives
3  * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
4  * $Revision: 1.1 $
5  * 
6  * This is free software.  You are permitted to use,
7  * redistribute, and modify it as specified in the file "COPYING".
8  */
9
10 #include <geekos/kthread.h>
11 #include <geekos/int.h>
12 #include <geekos/kassert.h>
13 #include <geekos/screen.h>
14 #include <geekos/synch.h>
15 #include <geekos/timer.h>
16
17 /*
18  * NOTES:
19  * - The GeekOS mutex and condition variable APIs are based on those
20  *   in pthreads.
21  * - Unlike disabling interrupts, mutexes offer NO protection against
22  *   concurrent execution of interrupt handlers.  Mutexes and
23  *   condition variables should only be used from kernel threads,
24  *   with interrupts enabled.
25  */
26
27 /* ----------------------------------------------------------------------
28  * Private functions
29  * ---------------------------------------------------------------------- */
30
31 /*
32  * The mutex is currently locked.
33  * Atomically reenable preemption and wait in the
34  * mutex's wait queue.
35  */
36 static void Mutex_Wait(struct Mutex *mutex)
37 {
38     KASSERT(mutex->state == MUTEX_LOCKED);
39     KASSERT(g_preemptionDisabled);
40
41     Disable_Interrupts();
42     g_preemptionDisabled = false;
43     Wait(&mutex->waitQueue);
44     g_preemptionDisabled = true;
45     Enable_Interrupts();
46 }
47
48 /*
49  * Lock given mutex.
50  * Preemption must be disabled.
51  */
52 static __inline__ void Mutex_Lock_Imp(struct Mutex* mutex)
53 {
54     KASSERT(g_preemptionDisabled);
55
56     /* Make sure we're not already holding the mutex */
57     KASSERT(!IS_HELD(mutex));
58
59     /* Wait until the mutex is in an unlocked state */
60     while (mutex->state == MUTEX_LOCKED) {
61         Mutex_Wait(mutex);
62     }
63
64     /* Now it's ours! */
65     mutex->state = MUTEX_LOCKED;
66     mutex->owner = g_currentThread;
67 }
68
69 /*
70  * Unlock given mutex.
71  * Preemption must be disabled.
72  */
73 static __inline__ void Mutex_Unlock_Imp(struct Mutex* mutex)
74 {
75     KASSERT(g_preemptionDisabled);
76
77     /* Make sure mutex was actually acquired by this thread. */
78     KASSERT(IS_HELD(mutex));
79
80     /* Unlock the mutex. */
81     mutex->state = MUTEX_UNLOCKED;
82     mutex->owner = 0;
83
84     /*
85      * If there are threads waiting to acquire the mutex,
86      * wake one of them up.  Note that it is legal to inspect
87      * the queue with interrupts enabled because preemption
88      * is disabled, and therefore we know that no thread can
89      * concurrently add itself to the queue.
90      */
91     if (!Is_Thread_Queue_Empty(&mutex->waitQueue)) {
92         Disable_Interrupts();
93         Wake_Up_One(&mutex->waitQueue);
94         Enable_Interrupts();
95     }
96 }
97
98 /* ----------------------------------------------------------------------
99  * Public functions
100  * ---------------------------------------------------------------------- */
101
102 /*
103  * Initialize given mutex.
104  */
105 void Mutex_Init(struct Mutex* mutex)
106 {
107     mutex->state = MUTEX_UNLOCKED;
108     mutex->owner = 0;
109     Clear_Thread_Queue(&mutex->waitQueue);
110 }
111
112 /*
113  * Lock given mutex.
114  */
115 void Mutex_Lock(struct Mutex* mutex)
116 {
117     KASSERT(Interrupts_Enabled());
118
119     g_preemptionDisabled = true;
120     Mutex_Lock_Imp(mutex);
121     g_preemptionDisabled = false;
122 }
123
124 /*
125  * Unlock given mutex.
126  */
127 void Mutex_Unlock(struct Mutex* mutex)
128 {
129     KASSERT(Interrupts_Enabled());
130
131     g_preemptionDisabled = true;
132     Mutex_Unlock_Imp(mutex);
133     g_preemptionDisabled = false;
134 }
135
136 /*
137  * Initialize given condition.
138  */
139 void Cond_Init(struct Condition* cond)
140 {
141     Clear_Thread_Queue(&cond->waitQueue);
142 }
143
144 /*
145  * Wait on given condition (protected by given mutex).
146  */
147 void Cond_Wait(struct Condition* cond, struct Mutex* mutex)
148 {
149     KASSERT(Interrupts_Enabled());
150
151     /* Ensure mutex is held. */
152     KASSERT(IS_HELD(mutex));
153
154     /* Turn off scheduling. */
155     g_preemptionDisabled = true;
156
157     /*
158      * Release the mutex, but leave preemption disabled.
159      * No other threads will be able to run before this thread
160      * is able to wait.  Therefore, this thread will not
161      * miss the eventual notification on the condition.
162      */
163     Mutex_Unlock_Imp(mutex);
164
165     /*
166      * Atomically reenable preemption and wait in the condition wait queue.
167      * Other threads can run while this thread is waiting,
168      * and eventually one of them will call Cond_Signal() or Cond_Broadcast()
169      * to wake up this thread.
170      * On wakeup, disable preemption again.
171      */
172     Disable_Interrupts();
173     g_preemptionDisabled = false;
174     Wait(&cond->waitQueue);
175     g_preemptionDisabled = true;
176     Enable_Interrupts();
177
178     /* Reacquire the mutex. */
179     Mutex_Lock_Imp(mutex);
180
181     /* Turn scheduling back on. */
182     g_preemptionDisabled = false;
183 }
184
185
186
187 struct timeout_data {
188   int pid;
189   int timed_out;
190   struct Thread_Queue * waitQueue;
191 };
192
193
194 static void timeout_cb(int id, void * arg) {
195   struct timeout_data * to_state = (struct timeout_data *)arg;
196   
197   to_state->timed_out = 1;
198   Wake_Up_Thread(to_state->waitQueue, to_state->pid);
199
200 }
201
202
203 /*
204  * Wait on given condition (protected by given mutex).
205  */
206 int Cond_Wait_Timeout(struct Condition* cond, struct Mutex* mutex, uint_t ms)
207 {
208   struct timeout_data to_state;
209   struct Kernel_Thread * self = Get_Current();
210
211   to_state.pid = self->pid;
212   to_state.timed_out = 0;
213   to_state.waitQueue = &cond->waitQueue;
214
215     KASSERT(Interrupts_Enabled());
216
217     /* Ensure mutex is held. */
218     KASSERT(IS_HELD(mutex));
219
220     /* Turn off scheduling. */
221     g_preemptionDisabled = true;
222
223
224
225     /*
226      * Release the mutex, but leave preemption disabled.
227      * No other threads will be able to run before this thread
228      * is able to wait.  Therefore, this thread will not
229      * miss the eventual notification on the condition.
230      */
231     Mutex_Unlock_Imp(mutex);
232
233
234     Start_Timer_MSecs(ms, timeout_cb, &to_state);
235
236     /*
237      * Atomically reenable preemption and wait in the condition wait queue.
238      * Other threads can run while this thread is waiting,
239      * and eventually one of them will call Cond_Signal() or Cond_Broadcast()
240      * to wake up this thread.
241      * On wakeup, disable preemption again.
242      */
243     Disable_Interrupts();
244     g_preemptionDisabled = false;
245     Wait(&cond->waitQueue);
246     g_preemptionDisabled = true;
247     Enable_Interrupts();
248
249     if (to_state.timed_out == 0) {  
250       /* Reacquire the mutex. */
251       Mutex_Lock_Imp(mutex);
252     }
253
254     /* Turn scheduling back on. */
255     g_preemptionDisabled = false;
256
257
258     return to_state.timed_out;
259 }
260
261 /*
262  * Wake up one thread waiting on the given condition.
263  * The mutex guarding the condition should be held!
264  */
265 void Cond_Signal(struct Condition* cond)
266 {
267     KASSERT(Interrupts_Enabled());
268     Disable_Interrupts();  /* prevent scheduling */
269     Wake_Up_One(&cond->waitQueue);
270     Enable_Interrupts();  /* resume scheduling */
271 }
272
273 /*
274  * Wake up all threads waiting on the given condition.
275  * The mutex guarding the condition should be held!
276  */
277 void Cond_Broadcast(struct Condition* cond)
278 {
279     KASSERT(Interrupts_Enabled());
280     Disable_Interrupts();  /* prevent scheduling */
281     Wake_Up(&cond->waitQueue);
282     Enable_Interrupts();  /* resume scheduling */
283 }