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