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