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