2 * Synchronization primitives
3 * Copyright (c) 2001,2004 David H. Hovemeyer <daveho@cs.umd.edu>
6 * This is free software. You are permitted to use,
7 * redistribute, and modify it as specified in the file "COPYING".
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>
18 * - The GeekOS mutex and condition variable APIs are based on those
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.
26 /* ----------------------------------------------------------------------
28 * ---------------------------------------------------------------------- */
31 * The mutex is currently locked.
32 * Atomically reenable preemption and wait in the
35 static void Mutex_Wait(struct Mutex *mutex)
37 KASSERT(mutex->state == MUTEX_LOCKED);
38 KASSERT(g_preemptionDisabled);
41 g_preemptionDisabled = false;
42 Wait(&mutex->waitQueue);
43 g_preemptionDisabled = true;
49 * Preemption must be disabled.
51 static __inline__ void Mutex_Lock_Imp(struct Mutex* mutex)
53 KASSERT(g_preemptionDisabled);
55 /* Make sure we're not already holding the mutex */
56 KASSERT(!IS_HELD(mutex));
58 /* Wait until the mutex is in an unlocked state */
59 while (mutex->state == MUTEX_LOCKED) {
64 mutex->state = MUTEX_LOCKED;
65 mutex->owner = g_currentThread;
70 * Preemption must be disabled.
72 static __inline__ void Mutex_Unlock_Imp(struct Mutex* mutex)
74 KASSERT(g_preemptionDisabled);
76 /* Make sure mutex was actually acquired by this thread. */
77 KASSERT(IS_HELD(mutex));
79 /* Unlock the mutex. */
80 mutex->state = MUTEX_UNLOCKED;
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.
90 if (!Is_Thread_Queue_Empty(&mutex->waitQueue)) {
92 Wake_Up_One(&mutex->waitQueue);
97 /* ----------------------------------------------------------------------
99 * ---------------------------------------------------------------------- */
102 * Initialize given mutex.
104 void Mutex_Init(struct Mutex* mutex)
106 mutex->state = MUTEX_UNLOCKED;
108 Clear_Thread_Queue(&mutex->waitQueue);
114 void Mutex_Lock(struct Mutex* mutex)
116 KASSERT(Interrupts_Enabled());
118 g_preemptionDisabled = true;
119 Mutex_Lock_Imp(mutex);
120 g_preemptionDisabled = false;
124 * Unlock given mutex.
126 void Mutex_Unlock(struct Mutex* mutex)
128 KASSERT(Interrupts_Enabled());
130 g_preemptionDisabled = true;
131 Mutex_Unlock_Imp(mutex);
132 g_preemptionDisabled = false;
136 * Initialize given condition.
138 void Cond_Init(struct Condition* cond)
140 Clear_Thread_Queue(&cond->waitQueue);
144 * Wait on given condition (protected by given mutex).
146 void Cond_Wait(struct Condition* cond, struct Mutex* mutex)
148 KASSERT(Interrupts_Enabled());
150 /* Ensure mutex is held. */
151 KASSERT(IS_HELD(mutex));
153 /* Turn off scheduling. */
154 g_preemptionDisabled = true;
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.
162 Mutex_Unlock_Imp(mutex);
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.
171 Disable_Interrupts();
172 g_preemptionDisabled = false;
173 Wait(&cond->waitQueue);
174 g_preemptionDisabled = true;
177 /* Reacquire the mutex. */
178 Mutex_Lock_Imp(mutex);
180 /* Turn scheduling back on. */
181 g_preemptionDisabled = false;
185 * Wake up one thread waiting on the given condition.
186 * The mutex guarding the condition should be held!
188 void Cond_Signal(struct Condition* cond)
190 KASSERT(Interrupts_Enabled());
191 Disable_Interrupts(); /* prevent scheduling */
192 Wake_Up_One(&cond->waitQueue);
193 Enable_Interrupts(); /* resume scheduling */
197 * Wake up all threads waiting on the given condition.
198 * The mutex guarding the condition should be held!
200 void Cond_Broadcast(struct Condition* cond)
202 KASSERT(Interrupts_Enabled());
203 Disable_Interrupts(); /* prevent scheduling */
204 Wake_Up(&cond->waitQueue);
205 Enable_Interrupts(); /* resume scheduling */