]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOConditionLock.cpp
d3d1ba88c6fef08fbce43d1eed5099e91c5d53ca
[apple/xnu.git] / iokit / Kernel / IOConditionLock.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* Copyright (c) 1997 Apple Computer, Inc. All rights reserved.
24 * Copyright (c) 1994-1996 NeXT Software, Inc. All rights reserved.
25 *
26 * AppleIOPSSafeCondLock.m. Lock object with exported condition variable,
27 * kernel version.
28 *
29 * HISTORY
30 * 1997-11-
31 * 01-Aug-91 Doug Mitchell at NeXT
32 * Created.
33 */
34
35 #include <IOKit/IOConditionLock.h>
36
37 #define super OSObject
38 OSDefineMetaClassAndStructors(IOConditionLock, OSObject)
39
40 bool IOConditionLock::initWithCondition(int inCondition, bool inIntr)
41 {
42 if (!super::init())
43 return false;
44
45 cond_interlock = IOLockAlloc();
46 sleep_interlock = IOLockAlloc();
47
48 condition = inCondition;
49 want_lock = false;
50 waiting = false;
51 interruptible = (inIntr) ? THREAD_INTERRUPTIBLE : THREAD_UNINT;
52
53 return cond_interlock && sleep_interlock;
54 }
55
56 IOConditionLock *IOConditionLock::withCondition(int condition, bool intr)
57 {
58 IOConditionLock *me = new IOConditionLock;
59
60 if (me && !me->initWithCondition(condition, intr)) {
61 me->release();
62 return 0;
63 }
64
65 return me;
66 }
67 void IOConditionLock::free()
68 {
69 if (cond_interlock)
70 IOLockFree(cond_interlock);
71 if (sleep_interlock)
72 IOLockFree(sleep_interlock);
73 super::free();
74 }
75
76 bool IOConditionLock::getInterruptible() const
77 {
78 return interruptible;
79 }
80
81 int IOConditionLock:: getCondition() const
82 {
83 return condition;
84 }
85
86 int IOConditionLock:: setCondition(int inCondition)
87 {
88 int old = condition;
89
90 condition = inCondition;
91 thread_wakeup_one((void *) &condition);
92
93 return old;
94 }
95
96 void IOConditionLock::unlock()
97 {
98 IOTakeLock(sleep_interlock);
99
100 thread_wakeup_one((void *) &condition);
101
102 want_lock = false;
103 if (waiting) {
104 waiting = false;
105 IOLockWakeup(sleep_interlock, this, /* one-thread */ false); // Wakeup everybody
106 }
107
108 IOUnlock(sleep_interlock);
109 }
110
111 void IOConditionLock::unlockWith(int inCondition)
112 {
113 IOTakeLock(sleep_interlock);
114 IOTakeLock(cond_interlock);
115
116 condition = inCondition;
117
118 IOUnlock(cond_interlock);
119 IOUnlock(sleep_interlock);
120
121 unlock();
122 }
123
124 bool IOConditionLock::tryLock()
125 {
126 bool result;
127
128 IOTakeLock(sleep_interlock);
129
130 result = !want_lock;
131 if (result)
132 want_lock = true;
133
134 IOUnlock(sleep_interlock);
135
136 return result;
137 }
138
139 int IOConditionLock::lock()
140 {
141 int thread_res = THREAD_AWAKENED;
142
143 IOTakeLock(sleep_interlock);
144
145 /* Try to acquire the want_lock bit. */
146 while (want_lock && thread_res == THREAD_AWAKENED)
147 {
148 waiting = true;
149 thread_res = IOLockSleep(sleep_interlock, (void *) this, interruptible);
150 }
151 if (thread_res == THREAD_AWAKENED)
152 want_lock = true;
153
154 IOUnlock(sleep_interlock);
155
156 return thread_res;
157 }
158
159 int IOConditionLock::lockWhen(int inCondition)
160 {
161 int thread_res;
162
163 do
164 {
165 /* First get the actual lock */
166 thread_res = lock();
167 if (thread_res != THREAD_AWAKENED)
168 break; // Failed to acquire lock
169
170 if (inCondition == condition)
171 break; // Hold lock and condition is expected value
172
173 /*
174 * Need to hold a IOTakeLock when we call thread_sleep().
175 * Both _cond_interlock and want_lock must be held to
176 * change _condition.
177 */
178 IOTakeLock(cond_interlock);
179 unlock(); // Release lock and sleep
180
181 /*
182 * this is the critical section on a multi in which
183 * another thread could hold _sleep_interlock, but they
184 * can't change _condition. Holding _cond_interlock here
185 * (until after assert_wait() is called from
186 * thread_sleep()) ensures that we'll be notified
187 * of changes in _condition.
188 */
189 assert_wait((void *) &condition, interruptible); /* assert event */
190 IOUnlock(cond_interlock); /* release the lock */
191 thread_res = thread_block(THREAD_CONTINUE_NULL); /* block ourselves */
192 } while (thread_res == THREAD_AWAKENED);
193
194 return thread_res;
195 }