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.


(no commit message)
[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.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
16 /*
17  * NOTES:
18  * - The GeekOS mutex and condition variable APIs are based on those
19  *   in pthreads.
20  * - Unlike disabling interrupts, mutexes offer NO protection against
21  *   concurrent execution of interrupt handlers.  Mutexes and
22  *   condition variables should only be used from kernel threads,
23  *   with interrupts enabled.
24  */
25
26 /* ----------------------------------------------------------------------
27  * Private functions
28  * ---------------------------------------------------------------------- */
29
30 /*
31  * The mutex is currently locked.
32  * Atomically reenable preemption and wait in the
33  * mutex's wait queue.
34  */
35 static void Mutex_Wait(struct Mutex *mutex)
36 {
37     KASSERT(mutex->state == MUTEX_LOCKED);
38     KASSERT(g_preemptionDisabled);
39
40     Disable_Interrupts();
41     g_preemptionDisabled = false;
42     Wait(&mutex->waitQueue);
43     g_preemptionDisabled = true;
44     Enable_Interrupts();
45 }
46
47 /*
48  * Lock given mutex.
49  * Preemption must be disabled.
50  */
51 static __inline__ void Mutex_Lock_Imp(struct Mutex* mutex)
52 {
53     KASSERT(g_preemptionDisabled);
54
55     /* Make sure we're not already holding the mutex */
56     KASSERT(!IS_HELD(mutex));
57
58     /* Wait until the mutex is in an unlocked state */
59     while (mutex->state == MUTEX_LOCKED) {
60         Mutex_Wait(mutex);
61     }
62
63     /* Now it's ours! */
64     mutex->state = MUTEX_LOCKED;
65     mutex->owner = g_currentThread;
66 }
67
68 /*
69  * Unlock given mutex.
70  * Preemption must be disabled.
71  */
72 static __inline__ void Mutex_Unlock_Imp(struct Mutex* mutex)
73 {
74     KASSERT(g_preemptionDisabled);
75
76     /* Make sure mutex was actually acquired by this thread. */
77     KASSERT(IS_HELD(mutex));
78
79     /* Unlock the mutex. */
80     mutex->state = MUTEX_UNLOCKED;
81     mutex->owner = 0;
82
83     /*
84      * If there are threads waiting to acquire the mutex,
85      * wake one of them up.  Note that it is legal to inspect
86      * the queue with interrupts enabled because preemption
87      * is disabled, and therefore we know that no thread can
88      * concurrently add itself to the queue.
89      */
90     if (!Is_Thread_Queue_Empty(&mutex->waitQueue)) {
91         Disable_Interrupts();
92         Wake_Up_One(&mutex->waitQueue);
93         Enable_Interrupts();
94     }
95 }
96
97 /* ----------------------------------------------------------------------
98  * Public functions
99  * ---------------------------------------------------------------------- */
100
101 /*
102  * Initialize given mutex.
103  */
104 void Mutex_Init(struct Mutex* mutex)
105 {
106     mutex->state = MUTEX_UNLOCKED;
107     mutex->owner = 0;
108     Clear_Thread_Queue(&mutex->waitQueue);
109 }
110
111 /*
112  * Lock given mutex.
113  */
114 void Mutex_Lock(struct Mutex* mutex)
115 {
116     KASSERT(Interrupts_Enabled());
117
118     g_preemptionDisabled = true;
119     Mutex_Lock_Imp(mutex);
120     g_preemptionDisabled = false;
121 }
122
123 /*
124  * Unlock given mutex.
125  */
126 void Mutex_Unlock(struct Mutex* mutex)
127 {
128     KASSERT(Interrupts_Enabled());
129
130     g_preemptionDisabled = true;
131     Mutex_Unlock_Imp(mutex);
132     g_preemptionDisabled = false;
133 }
134
135 /*
136  * Initialize given condition.
137  */
138 void Cond_Init(struct Condition* cond)
139 {
140     Clear_Thread_Queue(&cond->waitQueue);
141 }
142
143 /*
144  * Wait on given condition (protected by given mutex).
145  */
146 void Cond_Wait(struct Condition* cond, struct Mutex* mutex)
147 {
148     KASSERT(Interrupts_Enabled());
149
150     /* Ensure mutex is held. */
151     KASSERT(IS_HELD(mutex));
152
153     /* Turn off scheduling. */
154     g_preemptionDisabled = true;
155
156     /*
157      * Release the mutex, but leave preemption disabled.
158      * No other threads will be able to run before this thread
159      * is able to wait.  Therefore, this thread will not
160      * miss the eventual notification on the condition.
161      */
162     Mutex_Unlock_Imp(mutex);
163
164     /*
165      * Atomically reenable preemption and wait in the condition wait queue.
166      * Other threads can run while this thread is waiting,
167      * and eventually one of them will call Cond_Signal() or Cond_Broadcast()
168      * to wake up this thread.
169      * On wakeup, disable preemption again.
170      */
171     Disable_Interrupts();
172     g_preemptionDisabled = false;
173     Wait(&cond->waitQueue);
174     g_preemptionDisabled = true;
175     Enable_Interrupts();
176
177     /* Reacquire the mutex. */
178     Mutex_Lock_Imp(mutex);
179
180     /* Turn scheduling back on. */
181     g_preemptionDisabled = false;
182 }
183
184 /*
185  * Wake up one thread waiting on the given condition.
186  * The mutex guarding the condition should be held!
187  */
188 void Cond_Signal(struct Condition* cond)
189 {
190     KASSERT(Interrupts_Enabled());
191     Disable_Interrupts();  /* prevent scheduling */
192     Wake_Up_One(&cond->waitQueue);
193     Enable_Interrupts();  /* resume scheduling */
194 }
195
196 /*
197  * Wake up all threads waiting on the given condition.
198  * The mutex guarding the condition should be held!
199  */
200 void Cond_Broadcast(struct Condition* cond)
201 {
202     KASSERT(Interrupts_Enabled());
203     Disable_Interrupts();  /* prevent scheduling */
204     Wake_Up(&cond->waitQueue);
205     Enable_Interrupts();  /* resume scheduling */
206 }