]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOConditionLock.cpp
xnu-344.49.tar.gz
[apple/xnu.git] / iokit / Kernel / IOConditionLock.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
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.
1c79356b
A
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
40OSDefineMetaClassAndStructors(IOConditionLock, OSObject)
41
42bool 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
58IOConditionLock *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}
69void IOConditionLock::free()
70{
71 if (cond_interlock)
72 IOLockFree(cond_interlock);
73 if (sleep_interlock)
74 IOLockFree(sleep_interlock);
75 super::free();
76}
77
78bool IOConditionLock::getInterruptible() const
79{
80 return interruptible;
81}
82
83int IOConditionLock:: getCondition() const
84{
85 return condition;
86}
87
88int 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
98void 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;
9bccf70c 107 IOLockWakeup(sleep_interlock, this, /* one-thread */ false); // Wakeup everybody
1c79356b
A
108 }
109
110 IOUnlock(sleep_interlock);
111}
112
113void 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
126bool 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
141int 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;
9bccf70c 151 thread_res = IOLockSleep(sleep_interlock, (void *) this, interruptible);
1c79356b
A
152 }
153 if (thread_res == THREAD_AWAKENED)
154 want_lock = true;
155
156 IOUnlock(sleep_interlock);
157
158 return thread_res;
159}
160
161int 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 */
9bccf70c
A
192 IOUnlock(cond_interlock); /* release the lock */
193 thread_res = thread_block(THREAD_CONTINUE_NULL); /* block ourselves */
1c79356b
A
194 } while (thread_res == THREAD_AWAKENED);
195
196 return thread_res;
197}