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 /* 29 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 30 * 31 * IOTimerEventSource.cpp 32 * 33 * HISTORY 34 * 2-Feb-1999 Joe Liu (jliu) created. 35 * 1999-10-14 Godfrey van der Linden(gvdl) 36 * Revamped to use thread_call APIs 37 * 38 */ 39 40 #include <sys/cdefs.h> 41 42 __BEGIN_DECLS 43 #include <kern/thread_call.h> 44 __END_DECLS 45 46 #include <IOKit/assert.h> 47 #include <IOKit/system.h> 48 49 #include <IOKit/IOLib.h> 50 #include <IOKit/IOTimerEventSource.h> 51 #include <IOKit/IOWorkLoop.h> 52 53 #include <IOKit/IOTimeStamp.h> 54 55 #define super IOEventSource 56 OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource) 57 OSMetaClassDefineReservedUnused(IOTimerEventSource, 0); 58 OSMetaClassDefineReservedUnused(IOTimerEventSource, 1); 59 OSMetaClassDefineReservedUnused(IOTimerEventSource, 2); 60 OSMetaClassDefineReservedUnused(IOTimerEventSource, 3); 61 OSMetaClassDefineReservedUnused(IOTimerEventSource, 4); 62 OSMetaClassDefineReservedUnused(IOTimerEventSource, 5); 63 OSMetaClassDefineReservedUnused(IOTimerEventSource, 6); 64 OSMetaClassDefineReservedUnused(IOTimerEventSource, 7); 65 66 // 67 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used, 68 // not a subclassed implementation. 69 // 70 71 bool IOTimerEventSource::checkForWork() { return false; } 72 73 // Timeout handler function. This function is called by the kernel when 74 // the timeout interval expires. 75 // 76 void IOTimerEventSource::timeout(void *self) 77 { 78 IOTimerEventSource *me = (IOTimerEventSource *) self; 79 80 if (me->enabled && me->action) 81 { 82 IOWorkLoop * 83 wl = me->workLoop; 84 if (wl) 85 { 86 Action doit; 87 wl->closeGate(); 88 doit = (Action) me->action; 89 if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime)) 90 { 91 IOTimeStampConstant(IODBG_TIMES(IOTIMES_ACTION), 92 (unsigned int) doit, (unsigned int) me->owner); 93 (*doit)(me->owner, me); 94 } 95 wl->openGate(); 96 } 97 } 98 } 99 100 void IOTimerEventSource::timeoutAndRelease(void * self, void * count) 101 { 102 IOTimerEventSource *me = (IOTimerEventSource *) self; 103 104 if (me->enabled && me->action) 105 { 106 IOWorkLoop * 107 wl = me->reserved->workLoop; 108 if (wl) 109 { 110 Action doit; 111 wl->closeGate(); 112 doit = (Action) me->action; 113 if (doit && (me->reserved->calloutGeneration == (SInt32) count)) 114 { 115 IOTimeStampConstant(IODBG_TIMES(IOTIMES_ACTION), 116 (unsigned int) doit, (unsigned int) me->owner); 117 (*doit)(me->owner, me); 118 } 119 wl->openGate(); 120 } 121 } 122 123 me->reserved->workLoop->release(); 124 me->release(); 125 } 126 127 void IOTimerEventSource::setTimeoutFunc() 128 { 129 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used, 130 // not a subclassed implementation 131 reserved = IONew(ExpansionData, 1); 132 calloutEntry = (void *) thread_call_allocate((thread_call_func_t) &IOTimerEventSource::timeoutAndRelease, 133 (thread_call_param_t) this); 134 } 135 136 bool IOTimerEventSource::init(OSObject *inOwner, Action inAction) 137 { 138 if (!super::init(inOwner, (IOEventSource::Action) inAction) ) 139 return false; 140 141 setTimeoutFunc(); 142 if (!calloutEntry) 143 return false; 144 145 return true; 146 } 147 148 IOTimerEventSource * 149 IOTimerEventSource::timerEventSource(OSObject *inOwner, Action inAction) 150 { 151 IOTimerEventSource *me = new IOTimerEventSource; 152 153 if (me && !me->init(inOwner, inAction)) { 154 me->release(); 155 return 0; 156 } 157 158 return me; 159 } 160 161 void IOTimerEventSource::free() 162 { 163 if (calloutEntry) { 164 cancelTimeout(); 165 thread_call_free((thread_call_t) calloutEntry); 166 } 167 168 if (reserved) 169 IODelete(reserved, ExpansionData, 1); 170 171 super::free(); 172 } 173 174 void IOTimerEventSource::cancelTimeout() 175 { 176 if (reserved) 177 reserved->calloutGeneration++; 178 bool active = thread_call_cancel((thread_call_t) calloutEntry); 179 AbsoluteTime_to_scalar(&abstime) = 0; 180 if (active && reserved) 181 { 182 release(); 183 workLoop->release(); 184 } 185 } 186 187 void IOTimerEventSource::enable() 188 { 189 super::enable(); 190 if (kIOReturnSuccess != wakeAtTime(abstime)) 191 super::disable(); // Problem re-scheduling timeout ignore enable 192 } 193 194 void IOTimerEventSource::disable() 195 { 196 if (reserved) 197 reserved->calloutGeneration++; 198 bool active = thread_call_cancel((thread_call_t) calloutEntry); 199 super::disable(); 200 if (active && reserved) 201 { 202 release(); 203 workLoop->release(); 204 } 205 } 206 207 IOReturn IOTimerEventSource::setTimeoutTicks(UInt32 ticks) 208 { 209 return setTimeout(ticks, kTickScale); 210 } 211 212 IOReturn IOTimerEventSource::setTimeoutMS(UInt32 ms) 213 { 214 return setTimeout(ms, kMillisecondScale); 215 } 216 217 IOReturn IOTimerEventSource::setTimeoutUS(UInt32 us) 218 { 219 return setTimeout(us, kMicrosecondScale); 220 } 221 222 IOReturn IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor) 223 { 224 AbsoluteTime end; 225 226 clock_interval_to_deadline(interval, scale_factor, &end); 227 return wakeAtTime(end); 228 } 229 230 IOReturn IOTimerEventSource::setTimeout(mach_timespec_t interval) 231 { 232 AbsoluteTime end, nsecs; 233 234 clock_interval_to_absolutetime_interval 235 (interval.tv_nsec, kNanosecondScale, &nsecs); 236 clock_interval_to_deadline 237 (interval.tv_sec, NSEC_PER_SEC, &end); 238 ADD_ABSOLUTETIME(&end, &nsecs); 239 240 return wakeAtTime(end); 241 } 242 243 IOReturn IOTimerEventSource::setTimeout(AbsoluteTime interval) 244 { 245 AbsoluteTime end; 246 247 clock_get_uptime(&end); 248 ADD_ABSOLUTETIME(&end, &interval); 249 250 return wakeAtTime(end); 251 } 252 253 IOReturn IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks) 254 { 255 return wakeAtTime(ticks, kTickScale); 256 } 257 258 IOReturn IOTimerEventSource::wakeAtTimeMS(UInt32 ms) 259 { 260 return wakeAtTime(ms, kMillisecondScale); 261 } 262 263 IOReturn IOTimerEventSource::wakeAtTimeUS(UInt32 us) 264 { 265 return wakeAtTime(us, kMicrosecondScale); 266 } 267 268 IOReturn IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor) 269 { 270 AbsoluteTime end; 271 clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end); 272 273 return wakeAtTime(end); 274 } 275 276 IOReturn IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime) 277 { 278 AbsoluteTime end, nsecs; 279 280 clock_interval_to_absolutetime_interval 281 (inAbstime.tv_nsec, kNanosecondScale, &nsecs); 282 clock_interval_to_absolutetime_interval 283 (inAbstime.tv_sec, kSecondScale, &end); 284 ADD_ABSOLUTETIME(&end, &nsecs); 285 286 return wakeAtTime(end); 287 } 288 289 void IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop) 290 { 291 super::setWorkLoop(inWorkLoop); 292 if ( enabled && AbsoluteTime_to_scalar(&abstime) && workLoop ) 293 wakeAtTime(abstime); 294 } 295 296 IOReturn IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime) 297 { 298 if (!action) 299 return kIOReturnNoResources; 300 301 abstime = inAbstime; 302 if ( enabled && AbsoluteTime_to_scalar(&abstime) && workLoop ) 303 { 304 if (reserved) 305 { 306 retain(); 307 workLoop->retain(); 308 reserved->workLoop = workLoop; 309 reserved->calloutGeneration++; 310 if (thread_call_enter1_delayed((thread_call_t) calloutEntry, 311 (void *) reserved->calloutGeneration, abstime)) 312 { 313 release(); 314 workLoop->release(); 315 } 316 } 317 else 318 thread_call_enter_delayed((thread_call_t) calloutEntry, abstime); 319 } 320 321 return kIOReturnSuccess; 322 } 323