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 } 215