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