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 43OSDefineMetaClassAndStructors(IOConditionLock, OSObject) 44 45bool IOConditionLock::initWithCondition(int inCondition, bool inIntr) 46{ 47 if (!super::init()) 48 return false; 49 50 cond_interlock = IOLockAlloc(); 51 sleep_interlock = IOLockAlloc(); 52 53 condition = inCondition; 54 want_lock = false; 55 waiting = false; 56 interruptible = (inIntr) ? THREAD_INTERRUPTIBLE : THREAD_UNINT; 57 58 return cond_interlock && sleep_interlock; 59} 60 61IOConditionLock *IOConditionLock::withCondition(int condition, bool intr) 62{ 63 IOConditionLock *me = new IOConditionLock; 64 65 if (me && !me->initWithCondition(condition, intr)) { 66 me->release(); 67 return 0; 68 } 69 70 return me; 71} 72void IOConditionLock::free() 73{ 74 if (cond_interlock) 75 IOLockFree(cond_interlock); 76 if (sleep_interlock) 77 IOLockFree(sleep_interlock); 78 super::free(); 79} 80 81bool IOConditionLock::getInterruptible() const 82{ 83 return interruptible; 84} 85 86int IOConditionLock:: getCondition() const 87{ 88 return condition; 89} 90 91int IOConditionLock:: setCondition(int inCondition) 92{ 93 int old = condition; 94 95 condition = inCondition; 96 thread_wakeup_one((void *) &condition); 97 98 return old; 99} 100 101void IOConditionLock::unlock() 102{ 103 IOTakeLock(sleep_interlock); 104 105 thread_wakeup_one((void *) &condition); 106 107 want_lock = false; 108 if (waiting) { 109 waiting = false; 110 IOLockWakeup(sleep_interlock, this, /* one-thread */ false); // Wakeup everybody 111 } 112 113 IOUnlock(sleep_interlock); 114} 115 116void IOConditionLock::unlockWith(int inCondition) 117{ 118 IOTakeLock(sleep_interlock); 119 IOTakeLock(cond_interlock); 120 121 condition = inCondition; 122 123 IOUnlock(cond_interlock); 124 IOUnlock(sleep_interlock); 125 126 unlock(); 127} 128 129bool IOConditionLock::tryLock() 130{ 131 bool result; 132 133 IOTakeLock(sleep_interlock); 134 135 result = !want_lock; 136 if (result) 137 want_lock = true; 138 139 IOUnlock(sleep_interlock); 140 141 return result; 142} 143 144int IOConditionLock::lock() 145{ 146 int thread_res = THREAD_AWAKENED; 147 148 IOTakeLock(sleep_interlock); 149 150 /* Try to acquire the want_lock bit. */ 151 while (want_lock && thread_res == THREAD_AWAKENED) 152 { 153 waiting = true; 154 thread_res = IOLockSleep(sleep_interlock, (void *) this, interruptible); 155 } 156 if (thread_res == THREAD_AWAKENED) 157 want_lock = true; 158 159 IOUnlock(sleep_interlock); 160 161 return thread_res; 162} 163 164int IOConditionLock::lockWhen(int inCondition) 165{ 166 int thread_res; 167 168 do 169 { 170 /* First get the actual lock */ 171 thread_res = lock(); 172 if (thread_res != THREAD_AWAKENED) 173 break; // Failed to acquire lock 174 175 if (inCondition == condition) 176 break; // Hold lock and condition is expected value 177 178 /* 179 * Need to hold a IOTakeLock when we call thread_sleep(). 180 * Both _cond_interlock and want_lock must be held to 181 * change _condition. 182 */ 183 IOTakeLock(cond_interlock); 184 unlock(); // Release lock and sleep 185 186 /* 187 * this is the critical section on a multi in which 188 * another thread could hold _sleep_interlock, but they 189 * can't change _condition. Holding _cond_interlock here 190 * (until after assert_wait() is called from 191 * thread_sleep()) ensures that we'll be notified 192 * of changes in _condition. 193 */ 194 assert_wait((void *) &condition, interruptible); /* assert event */ 195 IOUnlock(cond_interlock); /* release the lock */ 196 thread_res = thread_block(THREAD_CONTINUE_NULL); /* block ourselves */ 197 } while (thread_res == THREAD_AWAKENED); 198 199 return thread_res; 200} 201