2 * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/system.h>
31 #include <IOKit/IOService.h>
32 #include <libkern/OSDebug.h>
33 #include <libkern/c++/OSContainers.h>
34 #include <libkern/c++/OSKext.h>
35 #include <libkern/c++/OSUnserialize.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOCommand.h>
38 #include <IOKit/IODeviceTreeSupport.h>
39 #include <IOKit/IODeviceMemory.h>
40 #include <IOKit/IOInterrupts.h>
41 #include <IOKit/IOInterruptController.h>
42 #include <IOKit/IOPlatformExpert.h>
43 #include <IOKit/IOMessage.h>
44 #include <IOKit/IOLib.h>
45 #include <IOKit/IOKitKeysPrivate.h>
46 #include <IOKit/IOBSD.h>
47 #include <IOKit/IOUserClient.h>
48 #include <IOKit/IOWorkLoop.h>
49 #include <IOKit/IOTimeStamp.h>
50 #include <IOKit/IOHibernatePrivate.h>
51 #include <IOKit/IOInterruptAccountingPrivate.h>
52 #include <IOKit/IOKernelReporters.h>
53 #include <IOKit/AppleKeyStoreInterface.h>
54 #include <IOKit/pwr_mgt/RootDomain.h>
55 #include <IOKit/IOCPU.h>
56 #include <mach/sync_policy.h>
57 #include <IOKit/assert.h>
58 #include <sys/errno.h>
59 #include <sys/kdebug.h>
62 #include <machine/pal_routines.h>
67 #define IOSERVICE_OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
69 // disabled since lockForArbitration() can be held externally
70 #define DEBUG_NOTIFIER_LOCKED 0
72 #include "IOServicePrivate.h"
73 #include "IOKitKernelInternal.h"
75 // take lockForArbitration before LOCKNOTIFY
77 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
79 #define super IORegistryEntry
81 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
83 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
84 OSDefineMetaClassAndStructors(_IOServiceNullNotifier
, IONotifier
)
86 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
88 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
90 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
92 OSDefineMetaClassAndStructors(IOResources
, IOService
)
94 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
96 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
98 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
100 static IOPlatformExpert
* gIOPlatform
;
101 static class IOPMrootDomain
* gIOPMRootDomain
;
102 const IORegistryPlane
* gIOServicePlane
;
103 const IORegistryPlane
* gIOPowerPlane
;
104 const OSSymbol
* gIODeviceMemoryKey
;
105 const OSSymbol
* gIOInterruptControllersKey
;
106 const OSSymbol
* gIOInterruptSpecifiersKey
;
108 const OSSymbol
* gIOResourcesKey
;
109 const OSSymbol
* gIOResourceMatchKey
;
110 const OSSymbol
* gIOResourceMatchedKey
;
111 const OSSymbol
* gIOProviderClassKey
;
112 const OSSymbol
* gIONameMatchKey
;
113 const OSSymbol
* gIONameMatchedKey
;
114 const OSSymbol
* gIOPropertyMatchKey
;
115 const OSSymbol
* gIOPropertyExistsMatchKey
;
116 const OSSymbol
* gIOLocationMatchKey
;
117 const OSSymbol
* gIOParentMatchKey
;
118 const OSSymbol
* gIOPathMatchKey
;
119 const OSSymbol
* gIOMatchCategoryKey
;
120 const OSSymbol
* gIODefaultMatchCategoryKey
;
121 const OSSymbol
* gIOMatchedServiceCountKey
;
123 const OSSymbol
* gIOServiceLegacyMatchingRegistryIDKey
;
126 const OSSymbol
* gIOMapperIDKey
;
127 const OSSymbol
* gIOUserClientClassKey
;
128 const OSSymbol
* gIOKitDebugKey
;
130 const OSSymbol
* gIOCommandPoolSizeKey
;
132 const OSSymbol
* gIOConsoleLockedKey
;
133 const OSSymbol
* gIOConsoleUsersKey
;
134 const OSSymbol
* gIOConsoleSessionUIDKey
;
135 const OSSymbol
* gIOConsoleSessionAuditIDKey
;
136 const OSSymbol
* gIOConsoleUsersSeedKey
;
137 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
138 const OSSymbol
* gIOConsoleSessionLoginDoneKey
;
139 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
140 const OSSymbol
* gIOConsoleSessionScreenLockedTimeKey
;
141 const OSSymbol
* gIOConsoleSessionScreenIsLockedKey
;
142 clock_sec_t gIOConsoleLockTime
;
143 static bool gIOConsoleLoggedIn
;
145 static OSBoolean
* gIOConsoleBooterLockState
;
146 static uint32_t gIOScreenLockState
;
148 static IORegistryEntry
* gIOChosenEntry
;
150 static int gIOResourceGenerationCount
;
152 const OSSymbol
* gIOServiceKey
;
153 const OSSymbol
* gIOPublishNotification
;
154 const OSSymbol
* gIOFirstPublishNotification
;
155 const OSSymbol
* gIOMatchedNotification
;
156 const OSSymbol
* gIOFirstMatchNotification
;
157 const OSSymbol
* gIOTerminatedNotification
;
158 const OSSymbol
* gIOWillTerminateNotification
;
160 const OSSymbol
* gIOGeneralInterest
;
161 const OSSymbol
* gIOBusyInterest
;
162 const OSSymbol
* gIOAppPowerStateInterest
;
163 const OSSymbol
* gIOPriorityPowerStateInterest
;
164 const OSSymbol
* gIOConsoleSecurityInterest
;
166 const OSSymbol
* gIOBSDKey
;
167 const OSSymbol
* gIOBSDNameKey
;
168 const OSSymbol
* gIOBSDMajorKey
;
169 const OSSymbol
* gIOBSDMinorKey
;
170 const OSSymbol
* gIOBSDUnitKey
;
172 const OSSymbol
* gAKSGetKey
;
173 #if defined(__i386__) || defined(__x86_64__)
174 const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
177 static OSDictionary
* gNotifications
;
178 static IORecursiveLock
* gNotificationLock
;
180 static IOService
* gIOResources
;
181 static IOService
* gIOServiceRoot
;
183 static OSOrderedSet
* gJobs
;
184 static semaphore_port_t gJobsSemaphore
;
185 static IOLock
* gJobsLock
;
186 static int gOutstandingJobs
;
187 static int gNumConfigThreads
;
188 static int gNumWaitingThreads
;
189 static IOLock
* gIOServiceBusyLock
;
192 static thread_t gIOTerminateThread
;
193 static thread_t gIOTerminateWorkerThread
;
194 static UInt32 gIOTerminateWork
;
195 static OSArray
* gIOTerminatePhase2List
;
196 static OSArray
* gIOStopList
;
197 static OSArray
* gIOStopProviderList
;
198 static OSArray
* gIOFinalizeList
;
200 static SInt32 gIOConsoleUsersSeed
;
201 static OSData
* gIOConsoleUsersSeedValue
;
203 extern const OSSymbol
* gIODTPHandleKey
;
205 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
207 static IOLock
* gIOConsoleUsersLock
;
208 static thread_call_t gIOConsoleLockCallout
;
209 static IONotifier
* gIOServiceNullNotifier
;
211 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
213 #define LOCKREADNOTIFY() \
214 IORecursiveLockLock( gNotificationLock )
215 #define LOCKWRITENOTIFY() \
216 IORecursiveLockLock( gNotificationLock )
217 #define LOCKWRITE2READNOTIFY()
218 #define UNLOCKNOTIFY() \
219 IORecursiveLockUnlock( gNotificationLock )
220 #define SLEEPNOTIFY(event) \
221 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
222 #define SLEEPNOTIFYTO(event, deadline) \
223 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
224 #define WAKEUPNOTIFY(event) \
225 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
227 #define randomDelay() \
228 int del = read_processor_clock(); \
229 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
232 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
234 #define queue_element(entry, element, type, field) do { \
235 vm_address_t __ele = (vm_address_t) (entry); \
236 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
237 (element) = (type) __ele; \
240 #define iterqueue(que, elt) \
241 for (queue_entry_t elt = queue_first(que); \
242 !queue_end(que, elt); \
243 elt = queue_next(elt))
245 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
247 struct IOInterruptAccountingReporter
{
248 IOSimpleReporter
* reporter
; /* Reporter responsible for communicating the statistics */
249 IOInterruptAccountingData
* statistics
; /* The live statistics values, if any */
252 struct ArbitrationLockQueueElement
{
261 static queue_head_t gArbitrationLockQueueActive
;
262 static queue_head_t gArbitrationLockQueueWaiting
;
263 static queue_head_t gArbitrationLockQueueFree
;
264 static IOLock
* gArbitrationLockQueueLock
;
266 bool IOService::isInactive( void ) const
267 { return( 0 != (kIOServiceInactiveState
& getState())); }
269 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
271 #if defined(__i386__) || defined(__x86_64__)
273 // Only used by the intel implementation of
274 // IOService::requireMaxBusStall(UInt32 ns)
275 // IOService::requireMaxInterruptDelay(uint32_t ns)
278 IOService
* fService
;
284 kCpuDelayBusStall
, kCpuDelayInterrupt
,
288 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
289 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
290 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
291 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
292 static OSNumber
* sCPULatencyHolder
[kCpuNumDelayTypes
];
293 static char sCPULatencyHolderName
[kCpuNumDelayTypes
][128];
294 static OSNumber
* sCPULatencySet
[kCpuNumDelayTypes
];
297 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
299 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
301 #endif /* defined(__i386__) || defined(__x86_64__) */
303 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
305 void IOService::initialize( void )
309 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
310 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
312 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
313 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
314 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
315 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
316 gIOPropertyExistsMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyExistsMatchKey
);
317 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
318 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
319 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
321 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
322 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
323 kIODefaultMatchCategoryKey
);
324 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
325 kIOMatchedServiceCountKey
);
327 gIOServiceLegacyMatchingRegistryIDKey
= OSSymbol::withCStringNoCopy(
328 kIOServiceLegacyMatchingRegistryIDKey
);
331 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
333 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
334 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
335 gIOResourceMatchedKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchedKey
);
337 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
338 gIOInterruptControllersKey
339 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
340 gIOInterruptSpecifiersKey
341 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
343 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
345 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
347 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
349 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
350 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
351 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
352 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
353 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
355 gIOBSDKey
= OSSymbol::withCStringNoCopy(kIOBSDKey
);
356 gIOBSDNameKey
= OSSymbol::withCStringNoCopy(kIOBSDNameKey
);
357 gIOBSDMajorKey
= OSSymbol::withCStringNoCopy(kIOBSDMajorKey
);
358 gIOBSDMinorKey
= OSSymbol::withCStringNoCopy(kIOBSDMinorKey
);
359 gIOBSDUnitKey
= OSSymbol::withCStringNoCopy(kIOBSDUnitKey
);
361 gNotifications
= OSDictionary::withCapacity( 1 );
362 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
363 kIOPublishNotification
);
364 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
365 kIOFirstPublishNotification
);
366 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
367 kIOMatchedNotification
);
368 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
369 kIOFirstMatchNotification
);
370 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
371 kIOTerminatedNotification
);
372 gIOWillTerminateNotification
= OSSymbol::withCStringNoCopy(
373 kIOWillTerminateNotification
);
374 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
376 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
377 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
378 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
379 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
381 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
382 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
383 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
384 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
385 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
386 gIOConsoleSessionScreenIsLockedKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenIsLockedKey
);
388 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
390 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
391 #if defined(__i386__) || defined(__x86_64__)
392 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
393 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
395 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++)
397 sCPULatencySet
[idx
] = OSNumber::withNumber(-1U, 32);
398 sCPULatencyHolder
[idx
] = OSNumber::withNumber(0ULL, 64);
399 assert(sCPULatencySet
[idx
] && sCPULatencyHolder
[idx
]);
401 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
403 gNotificationLock
= IORecursiveLockAlloc();
405 gAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
407 assert( gIOServicePlane
&& gIODeviceMemoryKey
408 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
409 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
410 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
411 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
412 && gIOPublishNotification
&& gIOMatchedNotification
413 && gIOTerminatedNotification
&& gIOServiceKey
414 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
415 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
416 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
418 gJobsLock
= IOLockAlloc();
419 gJobs
= OSOrderedSet::withCapacity( 10 );
421 gIOServiceBusyLock
= IOLockAlloc();
423 gIOConsoleUsersLock
= IOLockAlloc();
425 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
427 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
429 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
431 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
432 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
) );
434 gIOResources
= IOResources::resources();
435 assert( gIOResources
);
437 gIOServiceNullNotifier
= OSTypeAlloc(_IOServiceNullNotifier
);
438 assert(gIOServiceNullNotifier
);
440 gArbitrationLockQueueLock
= IOLockAlloc();
441 queue_init(&gArbitrationLockQueueActive
);
442 queue_init(&gArbitrationLockQueueWaiting
);
443 queue_init(&gArbitrationLockQueueFree
);
445 assert( gArbitrationLockQueueLock
);
447 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
448 gIOStopList
= OSArray::withCapacity( 16 );
449 gIOStopProviderList
= OSArray::withCapacity( 16 );
450 gIOFinalizeList
= OSArray::withCapacity( 16 );
451 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
453 // worker thread that is responsible for terminating / cleaning up threads
454 kernel_thread_start(&terminateThread
, NULL
, &gIOTerminateWorkerThread
);
455 assert(gIOTerminateWorkerThread
);
456 thread_set_thread_name(gIOTerminateWorkerThread
, "IOServiceTerminateThread");
459 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
461 #if defined(__i386__) || defined(__x86_64__)
464 const char *getCpuDelayBusStallHolderName(void);
465 const char *getCpuDelayBusStallHolderName(void) {
466 return sCPULatencyHolderName
[kCpuDelayBusStall
];
469 const char *getCpuInterruptDelayHolderName(void);
470 const char *getCpuInterruptDelayHolderName(void) {
471 return sCPULatencyHolderName
[kCpuDelayInterrupt
];
478 static UInt64
getDebugFlags( OSDictionary
* props
)
480 OSNumber
* debugProp
;
483 debugProp
= OSDynamicCast( OSNumber
,
484 props
->getObject( gIOKitDebugKey
));
486 debugFlags
= debugProp
->unsigned64BitValue();
488 debugFlags
= gIOKitDebug
;
490 return( debugFlags
);
493 static UInt64
getDebugFlags( IOService
* inst
)
496 OSNumber
* debugProp
;
499 prop
= inst
->copyProperty(gIOKitDebugKey
);
500 debugProp
= OSDynamicCast(OSNumber
, prop
);
502 debugFlags
= debugProp
->unsigned64BitValue();
504 debugFlags
= gIOKitDebug
;
506 OSSafeReleaseNULL(prop
);
508 return( debugFlags
);
512 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
514 // Probe a matched service and return an instance to be started.
515 // The default score is from the property table, & may be altered
516 // during probe to change the start order.
518 IOService
* IOService::probe( IOService
* provider
,
524 bool IOService::start( IOService
* provider
)
529 void IOService::stop( IOService
* provider
)
533 bool IOService::init( OSDictionary
* dictionary
)
537 ret
= super::init(dictionary
);
538 if (!ret
) return (false);
539 if (reserved
) return (true);
541 reserved
= IONew(ExpansionData
, 1);
542 if (!reserved
) return (false);
543 bzero(reserved
, sizeof(*reserved
));
546 * TODO: Improve on this. Previous efforts to more lazily allocate this
547 * lock based on the presence of specifiers ran into issues as some
548 * platforms set up the specifiers after IOService initialization.
550 * We may be able to get away with a global lock, as this should only be
551 * contended by IOReporting clients and driver start/stop (unless a
552 * driver wants to remove/add handlers in the course of normal operation,
553 * which should be unlikely).
555 reserved
->interruptStatisticsLock
= IOLockAlloc();
556 if (!reserved
->interruptStatisticsLock
) return (false);
561 bool IOService::init( IORegistryEntry
* from
,
562 const IORegistryPlane
* inPlane
)
566 ret
= super::init(from
, inPlane
);
567 if (!ret
) return (false);
568 if (reserved
) return (true);
570 reserved
= IONew(ExpansionData
, 1);
571 if (!reserved
) return (false);
572 bzero(reserved
, sizeof(*reserved
));
575 * TODO: Improve on this. Previous efforts to more lazily allocate this
576 * lock based on the presence of specifiers ran into issues as some
577 * platforms set up the specifiers after IOService initialization.
579 * We may be able to get away with a global lock, as this should only be
580 * contended by IOReporting clients and driver start/stop (unless a
581 * driver wants to remove/add handlers in the course of normal operation,
582 * which should be unlikely).
584 reserved
->interruptStatisticsLock
= IOLockAlloc();
585 if (!reserved
->interruptStatisticsLock
) return (false);
590 void IOService::free( void )
593 requireMaxBusStall(0);
594 requireMaxInterruptDelay(0);
595 if( getPropertyTable())
596 unregisterAllInterest();
600 if (reserved
->interruptStatisticsArray
) {
601 for (i
= 0; i
< reserved
->interruptStatisticsArrayCount
; i
++) {
602 if (reserved
->interruptStatisticsArray
[i
].reporter
)
603 reserved
->interruptStatisticsArray
[i
].reporter
->release();
606 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
609 if (reserved
->interruptStatisticsLock
)
610 IOLockFree(reserved
->interruptStatisticsLock
);
611 IODelete(reserved
, ExpansionData
, 1);
614 if (_numInterruptSources
&& _interruptSources
)
616 IOFree(_interruptSources
, _numInterruptSources
* sizeof(IOInterruptSource
));
617 _interruptSources
= 0;
624 * Attach in service plane
626 bool IOService::attach( IOService
* provider
)
630 AbsoluteTime deadline
;
631 int waitResult
= THREAD_AWAKENED
;
632 bool wait
, computeDeadline
= true;
636 if( gIOKitDebug
& kIOLogAttach
)
637 LOG( "%s::attach(%s)\n", getName(),
638 provider
->getName());
644 provider
->lockForArbitration();
645 if (provider
->__state
[0] & kIOServiceInactiveState
) ok
= false;
648 count
= provider
->getChildCount(gIOServicePlane
);
649 wait
= (count
> (kIOServiceBusyMax
- 4));
650 if (!wait
) ok
= attachToParent(provider
, gIOServicePlane
);
653 IOLog("stalling for detach from %s\n", provider
->getName());
654 IOLockLock( gIOServiceBusyLock
);
655 provider
->__state
[1] |= kIOServiceWaitDetachState
;
658 provider
->unlockForArbitration();
663 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
664 computeDeadline
= false;
666 assert_wait_deadline((event_t
)&provider
->__provider
, THREAD_UNINT
, deadline
);
667 IOLockUnlock( gIOServiceBusyLock
);
668 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
669 wait
= (waitResult
!= THREAD_TIMED_OUT
);
675 gIOServiceRoot
= this;
676 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
679 if (ok
&& !__provider
) (void) getProvider();
684 IOService
* IOService::getServiceRoot( void )
686 return( gIOServiceRoot
);
689 void IOService::detach( IOService
* provider
)
691 IOService
* newProvider
= 0;
695 if( gIOKitDebug
& kIOLogAttach
)
696 LOG("%s::detach(%s)\n", getName(), provider
->getName());
698 lockForArbitration();
700 uint64_t regID1
= provider
->getRegistryEntryID();
701 uint64_t regID2
= getRegistryEntryID();
705 (uintptr_t) (regID1
>> 32),
707 (uintptr_t) (regID2
>> 32));
709 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
710 && (provider
== getProvider()));
712 detachFromParent( provider
, gIOServicePlane
);
715 newProvider
= getProvider();
716 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
717 _adjustBusy( -busy
);
720 if (kIOServiceInactiveState
& __state
[0]) {
721 getMetaClass()->removeInstance(this);
722 IORemoveServicePlatformActions(this);
725 unlockForArbitration();
728 newProvider
->lockForArbitration();
729 newProvider
->_adjustBusy(1);
730 newProvider
->unlockForArbitration();
733 // check for last client detach from a terminated service
734 if( provider
->lockForArbitration( true ))
736 if (kIOServiceStartState
& __state
[1])
738 provider
->scheduleTerminatePhase2();
740 if( adjParent
) provider
->_adjustBusy( -1 );
741 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
742 && (0 == provider
->getClient())) {
743 provider
->scheduleFinalize(false);
746 IOLockLock( gIOServiceBusyLock
);
747 if (kIOServiceWaitDetachState
& provider
->__state
[1])
749 provider
->__state
[1] &= ~kIOServiceWaitDetachState
;
750 thread_wakeup(&provider
->__provider
);
752 IOLockUnlock( gIOServiceBusyLock
);
754 provider
->unlockForArbitration();
759 * Register instance - publish it for matching
762 void IOService::registerService( IOOptionBits options
)
768 enum { kMaxPathLen
= 256 };
769 enum { kMaxChars
= 63 };
771 IORegistryEntry
* parent
= this;
772 IORegistryEntry
* root
= getRegistryRoot();
773 while( parent
&& (parent
!= root
))
774 parent
= parent
->getParentEntry( gIOServicePlane
);
776 if( parent
!= root
) {
777 IOLog("%s: not registry member at registerService()\n", getName());
781 // Allow the Platform Expert to adjust this node.
782 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
785 IOInstallServicePlatformActions(this);
787 if( (this != gIOResources
)
788 && (kIOLogRegister
& gIOKitDebug
)) {
790 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
792 IOLog( "Registering: " );
795 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
798 if( len
> kMaxChars
) {
802 if( (skip
= strchr( path
, '/')))
808 IOLog( "%s\n", path
);
811 IOFree( pathBuf
, kMaxPathLen
);
814 startMatching( options
);
817 void IOService::startMatching( IOOptionBits options
)
819 IOService
* provider
;
822 bool needWake
= false;
827 lockForArbitration();
829 sync
= (options
& kIOServiceSynchronous
)
830 || ((provider
= getProvider())
831 && (provider
->__state
[1] & kIOServiceSynchronousState
));
833 if ( options
& kIOServiceAsynchronous
)
836 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigRunning
)))
837 && (0 == (__state
[0] & kIOServiceInactiveState
));
839 __state
[1] |= kIOServiceNeedConfigState
;
841 // __state[0] &= ~kIOServiceInactiveState;
843 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
844 // OSKernelStackRemaining(), getName());
847 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
851 __state
[1] |= kIOServiceSynchronousState
;
853 __state
[1] &= ~kIOServiceSynchronousState
;
855 if( needConfig
) prevBusy
= _adjustBusy( 1 );
857 unlockForArbitration();
862 IOLockLock( gIOServiceBusyLock
);
863 thread_wakeup( (event_t
) this/*&__state[1]*/ );
864 IOLockUnlock( gIOServiceBusyLock
);
866 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
868 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
872 if( (__state
[1] & kIOServiceNeedConfigState
))
873 doServiceMatch( options
);
875 lockForArbitration();
876 IOLockLock( gIOServiceBusyLock
);
878 waitAgain
= ((prevBusy
< (__state
[1] & kIOServiceBusyStateMask
))
879 && (0 == (__state
[0] & kIOServiceInactiveState
)));
882 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
884 __state
[1] &= ~kIOServiceSyncPubState
;
886 unlockForArbitration();
889 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
891 IOLockUnlock( gIOServiceBusyLock
);
893 thread_block(THREAD_CONTINUE_NULL
);
895 } while( waitAgain
);
899 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
901 OSDictionary
* table
;
911 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
914 set
= (OSSet
*) copyExistingServices( table
,
915 kIOServiceRegisteredState
,
916 kIOServiceExistingSet
);
921 count
+= set
->getCount();
924 allSet
->merge((const OSSet
*) set
);
932 if( getDebugFlags( table
) & kIOLogMatch
)
933 LOG("Matching service count = %ld\n", (long)count
);
935 newTables
->removeObject(table
);
939 while( (service
= (IOService
*) allSet
->getAnyObject())) {
940 service
->startMatching(kIOServiceAsynchronous
);
941 allSet
->removeObject(service
);
946 newTables
->release();
948 return( kIOReturnSuccess
);
951 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
952 IOOptionBits options
)
956 job
= new _IOServiceJob
;
957 if( job
&& !job
->init()) {
965 job
->options
= options
;
966 nub
->retain(); // thread will release()
974 * Called on a registered service to see if it matches
978 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
980 return( matchPropertyTable(table
) );
983 bool IOService::matchPropertyTable( OSDictionary
* table
)
989 * Called on a matched service to allocate resources
990 * before first driver is attached.
993 IOReturn
IOService::getResources( void )
995 return( kIOReturnSuccess
);
999 * Client/provider accessors
1002 IOService
* IOService::getProvider( void ) const
1004 IOService
* self
= (IOService
*) this;
1008 generation
= getRegistryEntryGenerationCount();
1009 if( __providerGeneration
== generation
)
1010 return( __provider
);
1012 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
1013 if( parent
== IORegistryEntry::getRegistryRoot())
1014 /* root is not an IOService */
1017 self
->__provider
= parent
;
1019 // save the count from before call to getParentEntry()
1020 self
->__providerGeneration
= generation
;
1025 IOWorkLoop
* IOService::getWorkLoop() const
1027 IOService
*provider
= getProvider();
1030 return provider
->getWorkLoop();
1035 OSIterator
* IOService::getProviderIterator( void ) const
1037 return( getParentIterator( gIOServicePlane
));
1040 IOService
* IOService::getClient( void ) const
1042 return( (IOService
*) getChildEntry( gIOServicePlane
));
1045 OSIterator
* IOService::getClientIterator( void ) const
1047 return( getChildIterator( gIOServicePlane
));
1050 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
1051 const IOService
* client
,
1052 const IOService
* provider
)
1054 _IOOpenServiceIterator
* inst
;
1059 inst
= new _IOOpenServiceIterator
;
1061 if( inst
&& !inst
->init()) {
1067 inst
->client
= client
;
1068 inst
->provider
= provider
;
1074 void _IOOpenServiceIterator::free()
1078 last
->unlockForArbitration();
1082 OSObject
* _IOOpenServiceIterator::getNextObject()
1087 last
->unlockForArbitration();
1089 while( (next
= (IOService
*) iter
->getNextObject())) {
1091 next
->lockForArbitration();
1092 if( (client
&& (next
->isOpen( client
)))
1093 || (provider
&& (provider
->isOpen( next
))) )
1095 next
->unlockForArbitration();
1103 bool _IOOpenServiceIterator::isValid()
1105 return( iter
->isValid() );
1108 void _IOOpenServiceIterator::reset()
1111 last
->unlockForArbitration();
1117 OSIterator
* IOService::getOpenProviderIterator( void ) const
1119 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
1122 OSIterator
* IOService::getOpenClientIterator( void ) const
1124 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
1128 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
1129 bool waitForFunction
,
1130 void *param1
, void *param2
,
1131 void *param3
, void *param4
)
1133 IOReturn result
= kIOReturnUnsupported
;
1134 IOService
*provider
;
1136 if (gIOPlatformFunctionHandlerSet
== functionName
)
1138 #if defined(__i386__) || defined(__x86_64__)
1139 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
1140 IOService
* target
= (IOService
*) param2
;
1141 bool enable
= (param3
!= 0);
1143 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
)
1144 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
1145 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
)
1146 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
1147 #endif /* defined(__i386__) || defined(__x86_64__) */
1150 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
1151 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
1152 param1
, param2
, param3
, param4
);
1158 IOReturn
IOService::callPlatformFunction( const char * functionName
,
1159 bool waitForFunction
,
1160 void *param1
, void *param2
,
1161 void *param3
, void *param4
)
1163 IOReturn result
= kIOReturnNoMemory
;
1164 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
1166 if (functionSymbol
!= 0) {
1167 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
1168 param1
, param2
, param3
, param4
);
1169 functionSymbol
->release();
1177 * Accessors for global services
1180 IOPlatformExpert
* IOService::getPlatform( void )
1182 return( gIOPlatform
);
1185 class IOPMrootDomain
* IOService::getPMRootDomain( void )
1187 return( gIOPMRootDomain
);
1190 IOService
* IOService::getResourceService( void )
1192 return( gIOResources
);
1195 void IOService::setPlatform( IOPlatformExpert
* platform
)
1197 gIOPlatform
= platform
;
1198 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1200 #if defined(__i386__) || defined(__x86_64__)
1202 static const char * keys
[kCpuNumDelayTypes
] = {
1203 kIOPlatformMaxBusDelay
, kIOPlatformMaxInterruptDelay
};
1204 const OSObject
* objs
[2];
1208 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++)
1210 objs
[0] = sCPULatencySet
[idx
];
1211 objs
[1] = sCPULatencyHolder
[idx
];
1212 array
= OSArray::withObjects(objs
, 2);
1214 platform
->setProperty(keys
[idx
], array
);
1217 #endif /* defined(__i386__) || defined(__x86_64__) */
1220 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
1222 gIOPMRootDomain
= rootDomain
;
1223 publishResource("IOKit");
1230 bool IOService::lockForArbitration( bool isSuccessRequired
)
1234 ArbitrationLockQueueElement
* element
;
1235 ArbitrationLockQueueElement
* active
;
1236 ArbitrationLockQueueElement
* waiting
;
1238 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
1240 // lock global access
1241 IOTakeLock( gArbitrationLockQueueLock
);
1243 // obtain an unused queue element
1244 if( !queue_empty( &gArbitrationLockQueueFree
)) {
1245 queue_remove_first( &gArbitrationLockQueueFree
,
1247 ArbitrationLockQueueElement
*,
1250 element
= IONew( ArbitrationLockQueueElement
, 1 );
1254 // prepare the queue element
1255 element
->thread
= IOThreadSelf();
1256 element
->service
= this;
1258 element
->required
= isSuccessRequired
;
1259 element
->aborted
= false;
1261 // determine whether this object is already locked (ie. on active queue)
1263 queue_iterate( &gArbitrationLockQueueActive
,
1265 ArbitrationLockQueueElement
*,
1268 if( active
->service
== element
->service
) {
1274 if( found
) { // this object is already locked
1276 // determine whether it is the same or a different thread trying to lock
1277 if( active
->thread
!= element
->thread
) { // it is a different thread
1279 ArbitrationLockQueueElement
* victim
= 0;
1281 // before placing this new thread on the waiting queue, we look for
1282 // a deadlock cycle...
1285 // determine whether the active thread holding the object we
1286 // want is waiting for another object to be unlocked
1288 queue_iterate( &gArbitrationLockQueueWaiting
,
1290 ArbitrationLockQueueElement
*,
1293 if( waiting
->thread
== active
->thread
) {
1294 assert( false == waiting
->aborted
);
1300 if( found
) { // yes, active thread waiting for another object
1302 // this may be a candidate for rejection if the required
1303 // flag is not set, should we detect a deadlock later on
1304 if( false == waiting
->required
)
1307 // find the thread that is holding this other object, that
1308 // is blocking the active thread from proceeding (fun :-)
1310 queue_iterate( &gArbitrationLockQueueActive
,
1311 active
, // (reuse active queue element)
1312 ArbitrationLockQueueElement
*,
1315 if( active
->service
== waiting
->service
) {
1321 // someone must be holding it or it wouldn't be waiting
1324 if( active
->thread
== element
->thread
) {
1326 // doh, it's waiting for the thread that originated
1327 // this whole lock (ie. current thread) -> deadlock
1328 if( false == element
->required
) { // willing to fail?
1330 // the originating thread doesn't have the required
1331 // flag, so it can fail
1332 success
= false; // (fail originating lock request)
1333 break; // (out of while)
1335 } else { // originating thread is not willing to fail
1337 // see if we came across a waiting thread that did
1338 // not have the 'required' flag set: we'll fail it
1341 // we do have a willing victim, fail it's lock
1342 victim
->aborted
= true;
1344 // take the victim off the waiting queue
1345 queue_remove( &gArbitrationLockQueueWaiting
,
1347 ArbitrationLockQueueElement
*,
1351 IOLockWakeup( gArbitrationLockQueueLock
,
1353 /* one thread */ true );
1355 // allow this thread to proceed (ie. wait)
1356 success
= true; // (put request on wait queue)
1357 break; // (out of while)
1360 // all the waiting threads we came across in
1361 // finding this loop had the 'required' flag
1362 // set, so we've got a deadlock we can't avoid
1363 panic("I/O Kit: Unrecoverable deadlock.");
1367 // repeat while loop, redefining active thread to be the
1368 // thread holding "this other object" (see above), and
1369 // looking for threads waiting on it; note the active
1370 // variable points to "this other object" already... so
1371 // there nothing to do in this else clause.
1373 } else { // no, active thread is not waiting for another object
1375 success
= true; // (put request on wait queue)
1376 break; // (out of while)
1380 if( success
) { // put the request on the waiting queue?
1381 kern_return_t wait_result
;
1383 // place this thread on the waiting queue and put it to sleep;
1384 // we place it at the tail of the queue...
1385 queue_enter( &gArbitrationLockQueueWaiting
,
1387 ArbitrationLockQueueElement
*,
1390 // declare that this thread will wait for a given event
1391 restart_sleep
: wait_result
= assert_wait( element
,
1392 element
->required
? THREAD_UNINT
1393 : THREAD_INTERRUPTIBLE
);
1395 // unlock global access
1396 IOUnlock( gArbitrationLockQueueLock
);
1398 // put thread to sleep, waiting for our event to fire...
1399 if (wait_result
== THREAD_WAITING
)
1400 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1403 // ...and we've been woken up; we might be in one of two states:
1404 // (a) we've been aborted and our queue element is not on
1405 // any of the three queues, but is floating around
1406 // (b) we're allowed to proceed with the lock and we have
1407 // already been moved from the waiting queue to the
1409 // ...plus a 3rd state, should the thread have been interrupted:
1410 // (c) we're still on the waiting queue
1412 // determine whether we were interrupted out of our sleep
1413 if( THREAD_INTERRUPTED
== wait_result
) {
1415 // re-lock global access
1416 IOTakeLock( gArbitrationLockQueueLock
);
1418 // determine whether we're still on the waiting queue
1420 queue_iterate( &gArbitrationLockQueueWaiting
,
1421 waiting
, // (reuse waiting queue element)
1422 ArbitrationLockQueueElement
*,
1425 if( waiting
== element
) {
1431 if( found
) { // yes, we're still on the waiting queue
1433 // determine whether we're willing to fail
1434 if( false == element
->required
) {
1436 // mark us as aborted
1437 element
->aborted
= true;
1439 // take us off the waiting queue
1440 queue_remove( &gArbitrationLockQueueWaiting
,
1442 ArbitrationLockQueueElement
*,
1444 } else { // we are not willing to fail
1446 // ignore interruption, go back to sleep
1451 // unlock global access
1452 IOUnlock( gArbitrationLockQueueLock
);
1454 // proceed as though this were a normal wake up
1455 wait_result
= THREAD_AWAKENED
;
1458 assert( THREAD_AWAKENED
== wait_result
);
1460 // determine whether we've been aborted while we were asleep
1461 if( element
->aborted
) {
1462 assert( false == element
->required
);
1464 // re-lock global access
1465 IOTakeLock( gArbitrationLockQueueLock
);
1467 action
= kPutOnFreeQueue
;
1469 } else { // we weren't aborted, so we must be ready to go :-)
1471 // we've already been moved from waiting to active queue
1475 } else { // the lock request is to be failed
1477 // return unused queue element to queue
1478 action
= kPutOnFreeQueue
;
1480 } else { // it is the same thread, recursive access is allowed
1482 // add one level of recursion
1485 // return unused queue element to queue
1486 action
= kPutOnFreeQueue
;
1489 } else { // this object is not already locked, so let this thread through
1490 action
= kPutOnActiveQueue
;
1494 // put the new element on a queue
1495 if( kPutOnActiveQueue
== action
) {
1496 queue_enter( &gArbitrationLockQueueActive
,
1498 ArbitrationLockQueueElement
*,
1500 } else if( kPutOnFreeQueue
== action
) {
1501 queue_enter( &gArbitrationLockQueueFree
,
1503 ArbitrationLockQueueElement
*,
1506 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1509 // unlock global access
1510 IOUnlock( gArbitrationLockQueueLock
);
1515 void IOService::unlockForArbitration( void )
1518 ArbitrationLockQueueElement
* element
;
1520 // lock global access
1521 IOTakeLock( gArbitrationLockQueueLock
);
1523 // find the lock element for this object (ie. on active queue)
1525 queue_iterate( &gArbitrationLockQueueActive
,
1527 ArbitrationLockQueueElement
*,
1530 if( element
->service
== this ) {
1538 // determine whether the lock has been taken recursively
1539 if( element
->count
> 1 ) {
1540 // undo one level of recursion
1545 // remove it from the active queue
1546 queue_remove( &gArbitrationLockQueueActive
,
1548 ArbitrationLockQueueElement
*,
1551 // put it on the free queue
1552 queue_enter( &gArbitrationLockQueueFree
,
1554 ArbitrationLockQueueElement
*,
1557 // determine whether a thread is waiting for object (head to tail scan)
1559 queue_iterate( &gArbitrationLockQueueWaiting
,
1561 ArbitrationLockQueueElement
*,
1564 if( element
->service
== this ) {
1570 if ( found
) { // we found an interested thread on waiting queue
1572 // remove it from the waiting queue
1573 queue_remove( &gArbitrationLockQueueWaiting
,
1575 ArbitrationLockQueueElement
*,
1578 // put it on the active queue
1579 queue_enter( &gArbitrationLockQueueActive
,
1581 ArbitrationLockQueueElement
*,
1584 // wake the waiting thread
1585 IOLockWakeup( gArbitrationLockQueueLock
,
1587 /* one thread */ true );
1591 // unlock global access
1592 IOUnlock( gArbitrationLockQueueLock
);
1595 uint32_t IOService::isLockedForArbitration(IOService
* service
)
1597 #if DEBUG_NOTIFIER_LOCKED
1599 ArbitrationLockQueueElement
* active
;
1601 // lock global access
1602 IOLockLock(gArbitrationLockQueueLock
);
1604 // determine whether this object is already locked (ie. on active queue)
1606 queue_iterate(&gArbitrationLockQueueActive
,
1608 ArbitrationLockQueueElement
*,
1611 if ((active
->thread
== IOThreadSelf())
1612 && (!service
|| (active
->service
== service
)))
1615 count
+= active
->count
;
1619 IOLockUnlock(gArbitrationLockQueueLock
);
1623 #else /* DEBUG_NOTIFIER_LOCKED */
1627 #endif /* DEBUG_NOTIFIER_LOCKED */
1630 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1633 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1634 context
, gIOServicePlane
);
1637 void IOService::applyToClients( IOServiceApplierFunction applier
,
1640 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1641 context
, gIOServicePlane
);
1650 // send a message to a client or interested party of this service
1651 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1652 void * argument
, vm_size_t argSize
)
1655 IOService
* service
;
1656 _IOServiceInterestNotifier
* notify
;
1658 if( (service
= OSDynamicCast( IOService
, client
)))
1659 ret
= service
->message( type
, this, argument
);
1661 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1663 _IOServiceNotifierInvocation invocation
;
1666 invocation
.thread
= current_thread();
1669 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1672 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1673 _IOServiceNotifierInvocation
*, link
);
1679 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1680 type
, this, argument
, argSize
);
1683 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1684 _IOServiceNotifierInvocation
*, link
);
1685 if( kIOServiceNotifyWaiter
& notify
->state
) {
1686 notify
->state
&= ~kIOServiceNotifyWaiter
;
1687 WAKEUPNOTIFY( notify
);
1692 ret
= kIOReturnSuccess
;
1695 ret
= kIOReturnBadArgument
;
1701 applyToInterestNotifiers(const IORegistryEntry
*target
,
1702 const OSSymbol
* typeOfInterest
,
1703 OSObjectApplierFunction applier
,
1706 OSArray
* copyArray
= 0;
1711 prop
= target
->copyProperty(typeOfInterest
);
1712 IOCommand
*notifyList
= OSDynamicCast(IOCommand
, prop
);
1715 copyArray
= OSArray::withCapacity(1);
1717 // iterate over queue, entry is set to each element in the list
1718 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1719 _IOServiceInterestNotifier
* notify
;
1721 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1722 copyArray
->setObject(notify
);
1731 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1732 (*applier
)(next
, context
);
1733 copyArray
->release();
1736 OSSafeReleaseNULL(prop
);
1739 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1740 OSObjectApplierFunction applier
,
1743 if (gIOGeneralInterest
== typeOfInterest
)
1744 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1745 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1748 struct MessageClientsContext
{
1749 IOService
* service
;
1756 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1759 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1761 ret
= context
->service
->messageClient( context
->type
,
1762 object
, context
->argument
, context
->argSize
);
1763 if( kIOReturnSuccess
!= ret
)
1767 // send a message to all clients
1768 IOReturn
IOService::messageClients( UInt32 type
,
1769 void * argument
, vm_size_t argSize
)
1771 MessageClientsContext context
;
1773 context
.service
= this;
1774 context
.type
= type
;
1775 context
.argument
= argument
;
1776 context
.argSize
= argSize
;
1777 context
.ret
= kIOReturnSuccess
;
1779 applyToInterested( gIOGeneralInterest
,
1780 &messageClientsApplier
, &context
);
1782 return( context
.ret
);
1785 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1786 IOOptionBits response
)
1788 return( kIOReturnUnsupported
);
1791 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1792 IOServiceInterestHandler handler
, void * target
, void * ref
)
1794 _IOServiceInterestNotifier
* notify
= 0;
1795 IOReturn rc
= kIOReturnError
;
1797 notify
= new _IOServiceInterestNotifier
;
1798 if (!notify
) return NULL
;
1800 if(notify
->init()) {
1801 rc
= registerInterestForNotifier(notify
, typeOfInterest
,
1802 handler
, target
, ref
);
1805 if (rc
!= kIOReturnSuccess
) {
1813 IOReturn
IOService::registerInterestForNotifier( IONotifier
*svcNotify
, const OSSymbol
* typeOfInterest
,
1814 IOServiceInterestHandler handler
, void * target
, void * ref
)
1816 IOReturn rc
= kIOReturnSuccess
;
1817 _IOServiceInterestNotifier
*notify
= 0;
1819 if( (typeOfInterest
!= gIOGeneralInterest
)
1820 && (typeOfInterest
!= gIOBusyInterest
)
1821 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1822 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
1823 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1824 return( kIOReturnBadArgument
);
1826 if (!svcNotify
|| !(notify
= OSDynamicCast(_IOServiceInterestNotifier
, svcNotify
)))
1827 return( kIOReturnBadArgument
);
1829 lockForArbitration();
1830 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1832 notify
->handler
= handler
;
1833 notify
->target
= target
;
1835 notify
->state
= kIOServiceNotifyEnable
;
1841 // Get the head of the notifier linked list
1842 IOCommand
* notifyList
;
1843 OSObject
* obj
= copyProperty( typeOfInterest
);
1844 if (!(notifyList
= OSDynamicCast(IOCommand
, obj
))) {
1845 notifyList
= OSTypeAlloc(IOCommand
);
1848 bool ok
= setProperty( typeOfInterest
, notifyList
);
1849 notifyList
->release();
1850 if (!ok
) notifyList
= 0;
1853 if (obj
) obj
->release();
1856 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1857 notify
->retain(); // ref'ed while in list
1863 rc
= kIOReturnNotReady
;
1865 unlockForArbitration();
1870 static void cleanInterestList( OSObject
* head
)
1872 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1877 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1878 queue_next(entry
) = queue_prev(entry
) = 0;
1880 _IOServiceInterestNotifier
* notify
;
1882 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1888 void IOService::unregisterAllInterest( void )
1892 prop
= copyProperty(gIOGeneralInterest
);
1893 cleanInterestList(prop
);
1894 OSSafeReleaseNULL(prop
);
1896 prop
= copyProperty(gIOBusyInterest
);
1897 cleanInterestList(prop
);
1898 OSSafeReleaseNULL(prop
);
1900 prop
= copyProperty(gIOAppPowerStateInterest
);
1901 cleanInterestList(prop
);
1902 OSSafeReleaseNULL(prop
);
1904 prop
= copyProperty(gIOPriorityPowerStateInterest
);
1905 cleanInterestList(prop
);
1906 OSSafeReleaseNULL(prop
);
1908 prop
= copyProperty(gIOConsoleSecurityInterest
);
1909 cleanInterestList(prop
);
1910 OSSafeReleaseNULL(prop
);
1914 * _IOServiceInterestNotifier
1917 // wait for all threads, other than the current one,
1918 // to exit the handler
1920 void _IOServiceInterestNotifier::wait()
1922 _IOServiceNotifierInvocation
* next
;
1927 queue_iterate( &handlerInvocations
, next
,
1928 _IOServiceNotifierInvocation
*, link
) {
1929 if( next
->thread
!= current_thread() ) {
1935 state
|= kIOServiceNotifyWaiter
;
1942 void _IOServiceInterestNotifier::free()
1944 assert( queue_empty( &handlerInvocations
));
1948 void _IOServiceInterestNotifier::remove()
1952 if( queue_next( &chain
)) {
1954 queue_next( &chain
) = queue_prev( &chain
) = 0;
1958 state
&= ~kIOServiceNotifyEnable
;
1967 bool _IOServiceInterestNotifier::disable()
1973 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1974 state
&= ~kIOServiceNotifyEnable
;
1983 void _IOServiceInterestNotifier::enable( bool was
)
1987 state
|= kIOServiceNotifyEnable
;
1989 state
&= ~kIOServiceNotifyEnable
;
1993 bool _IOServiceInterestNotifier::init()
1995 queue_init( &handlerInvocations
);
1996 return (OSObject::init());
1998 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004 #define tailQ(o) setObject(o)
2005 #define headQ(o) setObject(0, o)
2006 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
2008 static void _workLoopAction( IOWorkLoop::Action action
,
2009 IOService
* service
,
2010 void * p0
= 0, void * p1
= 0,
2011 void * p2
= 0, void * p3
= 0 )
2015 if( (wl
= service
->getWorkLoop())) {
2017 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
2020 (*action
)( service
, p0
, p1
, p2
, p3
);
2023 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
2027 // if its our only provider
2028 ok
= isParent( provider
, gIOServicePlane
, true);
2032 provider
->terminateClient( this, options
| kIOServiceRecursing
);
2033 ok
= (0 != (kIOServiceInactiveState
& __state
[0]));
2040 bool IOService::terminatePhase1( IOOptionBits options
)
2045 OSArray
* makeInactive
;
2046 OSArray
* waitingInactive
;
2047 int waitResult
= THREAD_AWAKENED
;
2051 bool startPhase2
= false;
2053 TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options
);
2055 uint64_t regID
= getRegistryEntryID();
2057 IOSERVICE_TERMINATE_PHASE1
,
2059 (uintptr_t) (regID
>> 32),
2061 (uintptr_t) options
);
2064 if( options
& kIOServiceRecursing
) {
2065 lockForArbitration();
2066 if (0 == (kIOServiceInactiveState
& __state
[0]))
2068 __state
[0] |= kIOServiceInactiveState
;
2069 __state
[1] |= kIOServiceRecursing
| kIOServiceTermPhase1State
;
2071 unlockForArbitration();
2077 makeInactive
= OSArray::withCapacity( 16 );
2078 waitingInactive
= OSArray::withCapacity( 16 );
2079 if(!makeInactive
|| !waitingInactive
) return( false );
2086 didInactive
= victim
->lockForArbitration( true );
2089 uint64_t regID1
= victim
->getRegistryEntryID();
2090 IOServiceTrace(IOSERVICE_TERM_SET_INACTIVE
,
2092 (uintptr_t) (regID1
>> 32),
2093 (uintptr_t) victim
->__state
[1],
2096 enum { kRP1
= kIOServiceRecursing
| kIOServiceTermPhase1State
};
2097 didInactive
= (kRP1
== (victim
->__state
[1] & kRP1
))
2098 || (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
2102 // a multiply attached IOService can be visited twice
2103 if (-1U == waitingInactive
->getNextIndexOfObject(victim
, 0)) do
2105 IOLockLock(gIOServiceBusyLock
);
2106 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
2108 TLOG("%s[0x%qx]::waitPhase1(%s[0x%qx])\n",
2109 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2110 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
2111 victim
->unlockForArbitration();
2112 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
2114 IOLockUnlock(gIOServiceBusyLock
);
2116 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2117 TLOG("%s[0x%qx]::did waitPhase1(%s[0x%qx])\n",
2118 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2119 victim
->lockForArbitration();
2122 while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2126 victim
->__state
[0] |= kIOServiceInactiveState
;
2127 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
2128 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
2129 victim
->__state
[1] &= ~kIOServiceRecursing
;
2130 victim
->__state
[1] |= kIOServiceTermPhase1State
;
2131 waitingInactive
->headQ(victim
);
2134 if (kIOServiceTerminateNeedWillTerminate
& options
)
2136 victim
->__state
[1] |= kIOServiceNeedWillTerminate
;
2139 victim
->_adjustBusy( 1 );
2141 victim
->unlockForArbitration();
2143 if( victim
== this) startPhase2
= didInactive
;
2146 OSArray
* notifiers
;
2147 notifiers
= victim
->copyNotifiers(gIOTerminatedNotification
, 0, 0xffffffff);
2148 victim
->invokeNotifiers(¬ifiers
);
2150 IOUserClient::destroyUserReferences( victim
);
2152 iter
= victim
->getClientIterator();
2154 while( (client
= (IOService
*) iter
->getNextObject())) {
2155 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n",
2156 client
->getName(), client
->getRegistryEntryID(),
2157 victim
->getName(), victim
->getRegistryEntryID(), (long long)options
);
2158 ok
= client
->requestTerminate( victim
, options
);
2159 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n",
2160 client
->getName(), client
->getRegistryEntryID(),
2161 victim
->getName(), victim
->getRegistryEntryID(), ok
);
2163 uint64_t regID1
= client
->getRegistryEntryID();
2164 uint64_t regID2
= victim
->getRegistryEntryID();
2166 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
2167 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
2169 (uintptr_t) (regID1
>> 32),
2171 (uintptr_t) (regID2
>> 32));
2174 makeInactive
->setObject( client
);
2180 victim
= (IOService
*) makeInactive
->getObject(0);
2183 makeInactive
->removeObject(0);
2186 makeInactive
->release();
2188 while ((victim
= (IOService
*) waitingInactive
->getObject(0)))
2191 waitingInactive
->removeObject(0);
2193 victim
->lockForArbitration();
2194 victim
->__state
[1] &= ~kIOServiceTermPhase1State
;
2195 if (kIOServiceTerm1WaiterState
& victim
->__state
[1])
2197 victim
->__state
[1] &= ~kIOServiceTerm1WaiterState
;
2198 TLOG("%s[0x%qx]::wakePhase1\n", victim
->getName(), victim
->getRegistryEntryID());
2199 IOLockLock( gIOServiceBusyLock
);
2200 thread_wakeup( (event_t
) &victim
->__state
[1]);
2201 IOLockUnlock( gIOServiceBusyLock
);
2203 victim
->unlockForArbitration();
2206 waitingInactive
->release();
2211 lockForArbitration();
2212 scheduleTerminatePhase2(options
);
2213 unlockForArbitration();
2220 void IOService::setTerminateDefer(IOService
* provider
, bool defer
)
2222 lockForArbitration();
2223 if (defer
) __state
[1] |= kIOServiceStartState
;
2224 else __state
[1] &= ~kIOServiceStartState
;
2225 unlockForArbitration();
2227 if (provider
&& !defer
)
2229 provider
->lockForArbitration();
2230 provider
->scheduleTerminatePhase2();
2231 provider
->unlockForArbitration();
2235 // Must call this while holding gJobsLock
2236 void IOService::waitToBecomeTerminateThread(void)
2238 IOLockAssert(gJobsLock
, kIOLockAssertOwned
);
2241 wait
= (gIOTerminateThread
!= THREAD_NULL
);
2243 IOLockSleep(gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
2246 gIOTerminateThread
= current_thread();
2249 // call with lockForArbitration
2250 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
2252 AbsoluteTime deadline
;
2254 int waitResult
= THREAD_AWAKENED
;
2255 bool wait
= false, haveDeadline
= false;
2257 if (!(__state
[0] & kIOServiceInactiveState
)) return;
2259 regID1
= getRegistryEntryID();
2261 IOSERVICE_TERM_SCHED_PHASE2
,
2263 (uintptr_t) (regID1
>> 32),
2264 (uintptr_t) __state
[1],
2265 (uintptr_t) options
);
2267 if (__state
[1] & kIOServiceTermPhase1State
) return;
2270 unlockForArbitration();
2271 options
|= kIOServiceRequired
;
2272 IOLockLock( gJobsLock
);
2274 if( (options
& kIOServiceSynchronous
)
2275 && (current_thread() != gIOTerminateThread
)) {
2277 waitToBecomeTerminateThread();
2278 gIOTerminatePhase2List
->setObject( this );
2282 while( gIOTerminateWork
)
2283 terminateWorker( options
);
2284 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
2286 /* wait for the victim to go non-busy */
2287 if( !haveDeadline
) {
2288 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
2289 haveDeadline
= true;
2291 /* let others do work while we wait */
2292 gIOTerminateThread
= 0;
2293 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2294 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
2295 deadline
, THREAD_UNINT
);
2296 if (__improbable(waitResult
== THREAD_TIMED_OUT
)) {
2297 panic("%s[0x%qx]::terminate(kIOServiceSynchronous) timeout\n", getName(), getRegistryEntryID());
2299 waitToBecomeTerminateThread();
2301 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
2303 gIOTerminateThread
= 0;
2304 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2307 // ! kIOServiceSynchronous
2309 gIOTerminatePhase2List
->setObject( this );
2310 if( 0 == gIOTerminateWork
++) {
2311 assert(gIOTerminateWorkerThread
);
2312 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2316 IOLockUnlock( gJobsLock
);
2317 lockForArbitration();
2321 __attribute__((__noreturn__
))
2322 void IOService::terminateThread( void * arg
, wait_result_t waitResult
)
2324 // IOLockSleep re-acquires the lock on wakeup, so we only need to do this once
2325 IOLockLock(gJobsLock
);
2327 if (gIOTerminateThread
!= gIOTerminateWorkerThread
) {
2328 waitToBecomeTerminateThread();
2331 while (gIOTerminateWork
)
2332 terminateWorker( (uintptr_t)arg
);
2334 gIOTerminateThread
= 0;
2335 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2336 IOLockSleep(gJobsLock
, &gIOTerminateWork
, THREAD_UNINT
);
2340 void IOService::scheduleStop( IOService
* provider
)
2342 uint64_t regID1
= getRegistryEntryID();
2343 uint64_t regID2
= provider
->getRegistryEntryID();
2345 TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1
, provider
->getName(), regID2
);
2347 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
2349 (uintptr_t) (regID1
>> 32),
2351 (uintptr_t) (regID2
>> 32));
2353 IOLockLock( gJobsLock
);
2354 gIOStopList
->tailQ( this );
2355 gIOStopProviderList
->tailQ( provider
);
2357 if( 0 == gIOTerminateWork
++) {
2358 assert(gIOTerminateWorkerThread
);
2359 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2362 IOLockUnlock( gJobsLock
);
2365 void IOService::scheduleFinalize(bool now
)
2367 uint64_t regID1
= getRegistryEntryID();
2369 TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1
);
2371 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
2373 (uintptr_t) (regID1
>> 32),
2376 if (now
|| IOUserClient::finalizeUserReferences(this))
2378 IOLockLock( gJobsLock
);
2379 gIOFinalizeList
->tailQ(this);
2380 if( 0 == gIOTerminateWork
++) {
2381 assert(gIOTerminateWorkerThread
);
2382 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2384 IOLockUnlock( gJobsLock
);
2388 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
2393 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
2395 if( false == *defer
) {
2397 if( lockForArbitration( true )) {
2398 if( false == provider
->handleIsOpen( this ))
2399 scheduleStop( provider
);
2402 message( kIOMessageServiceIsRequestingClose
, provider
, (void *)(uintptr_t) options
);
2403 if( false == provider
->handleIsOpen( this ))
2404 scheduleStop( provider
);
2407 unlockForArbitration();
2414 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
2415 OSArray
* doPhase2List
,
2416 void *unused2 __unused
,
2417 void *unused3 __unused
)
2422 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2424 iter
= victim
->getClientIterator();
2426 while( (client
= (IOService
*) iter
->getNextObject())) {
2428 regID1
= client
->getRegistryEntryID();
2429 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2430 client
->getName(), regID1
,
2431 victim
->getName(), regID2
, (long long)options
);
2433 IOSERVICE_TERMINATE_WILL
,
2435 (uintptr_t) (regID1
>> 32),
2437 (uintptr_t) (regID2
>> 32));
2439 ok
= client
->willTerminate( victim
, options
);
2440 doPhase2List
->tailQ( client
);
2446 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2447 void *unused1 __unused
, void *unused2 __unused
,
2448 void *unused3 __unused
)
2453 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2455 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *)(uintptr_t) options
);
2457 iter
= victim
->getClientIterator();
2459 while( (client
= (IOService
*) iter
->getNextObject())) {
2461 regID1
= client
->getRegistryEntryID();
2462 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2463 client
->getName(), regID1
,
2464 victim
->getName(), regID2
, (long long)options
);
2466 client
->didTerminate( victim
, options
, &defer
);
2469 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2470 : IOSERVICE_TERMINATE_DID
),
2472 (uintptr_t) (regID1
>> 32),
2474 (uintptr_t) (regID2
>> 32));
2476 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2477 client
->getName(), regID1
,
2478 victim
->getName(), regID2
, defer
);
2485 void IOService::actionWillStop( IOService
* victim
, IOOptionBits options
,
2486 void *unused1 __unused
, void *unused2 __unused
,
2487 void *unused3 __unused
)
2490 IOService
* provider
;
2492 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2494 iter
= victim
->getProviderIterator();
2496 while( (provider
= (IOService
*) iter
->getNextObject())) {
2498 regID1
= provider
->getRegistryEntryID();
2499 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2500 victim
->getName(), regID2
,
2501 provider
->getName(), regID1
, (long long)options
);
2503 IOSERVICE_TERMINATE_WILL
,
2505 (uintptr_t) (regID2
>> 32),
2507 (uintptr_t) (regID1
>> 32));
2509 ok
= victim
->willTerminate( provider
, options
);
2515 void IOService::actionDidStop( IOService
* victim
, IOOptionBits options
,
2516 void *unused1 __unused
, void *unused2 __unused
,
2517 void *unused3 __unused
)
2520 IOService
* provider
;
2522 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2524 iter
= victim
->getProviderIterator();
2526 while( (provider
= (IOService
*) iter
->getNextObject())) {
2528 regID1
= provider
->getRegistryEntryID();
2529 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2530 victim
->getName(), regID2
,
2531 provider
->getName(), regID1
, (long long)options
);
2532 victim
->didTerminate( provider
, options
, &defer
);
2535 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2536 : IOSERVICE_TERMINATE_DID
),
2538 (uintptr_t) (regID2
>> 32),
2540 (uintptr_t) (regID1
>> 32));
2542 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2543 victim
->getName(), regID2
,
2544 provider
->getName(), regID1
, defer
);
2551 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2552 void *unused1 __unused
, void *unused2 __unused
,
2553 void *unused3 __unused
)
2555 uint64_t regID1
= victim
->getRegistryEntryID();
2556 TLOG("%s[0x%qx]::finalize(%08llx)\n", victim
->getName(), regID1
, (long long)options
);
2558 IOSERVICE_TERMINATE_FINALIZE
,
2560 (uintptr_t) (regID1
>> 32),
2563 victim
->finalize( options
);
2566 void IOService::actionStop( IOService
* provider
, IOService
* client
,
2567 void *unused1 __unused
, void *unused2 __unused
,
2568 void *unused3 __unused
)
2570 uint64_t regID1
= provider
->getRegistryEntryID();
2571 uint64_t regID2
= client
->getRegistryEntryID();
2573 TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2575 IOSERVICE_TERMINATE_STOP
,
2577 (uintptr_t) (regID1
>> 32),
2579 (uintptr_t) (regID2
>> 32));
2581 client
->stop( provider
);
2582 if( provider
->isOpen( client
))
2583 provider
->close( client
);
2585 TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2586 client
->detach( provider
);
2589 void IOService::terminateWorker( IOOptionBits options
)
2591 OSArray
* doPhase2List
;
2592 OSArray
* didPhase2List
;
2598 IOService
* provider
;
2604 options
|= kIOServiceRequired
;
2606 doPhase2List
= OSArray::withCapacity( 16 );
2607 didPhase2List
= OSArray::withCapacity( 16 );
2608 freeList
= OSSet::withCapacity( 16 );
2609 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
2613 workDone
= gIOTerminateWork
;
2615 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
2618 gIOTerminatePhase2List
->removeObject(0);
2619 IOLockUnlock( gJobsLock
);
2621 uint64_t regID1
= victim
->getRegistryEntryID();
2623 IOSERVICE_TERM_START_PHASE2
,
2625 (uintptr_t) (regID1
>> 32),
2631 doPhase2
= victim
->lockForArbitration( true );
2633 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
2636 uint64_t regID1
= victim
->getRegistryEntryID();
2638 IOSERVICE_TERM_TRY_PHASE2
,
2640 (uintptr_t) (regID1
>> 32),
2641 (uintptr_t) victim
->__state
[1],
2644 doPhase2
= (0 == (victim
->__state
[1] &
2645 (kIOServiceTermPhase1State
2646 | kIOServiceTermPhase2State
2647 | kIOServiceConfigState
)));
2649 if (doPhase2
&& (iter
= victim
->getClientIterator())) {
2650 while (doPhase2
&& (client
= (IOService
*) iter
->getNextObject())) {
2651 doPhase2
= (0 == (client
->__state
[1] & kIOServiceStartState
));
2654 uint64_t regID1
= client
->getRegistryEntryID();
2656 IOSERVICE_TERM_UC_DEFER
,
2658 (uintptr_t) (regID1
>> 32),
2659 (uintptr_t) client
->__state
[1],
2661 TLOG("%s[0x%qx]::defer phase2(%s[0x%qx])\n",
2662 victim
->getName(), victim
->getRegistryEntryID(),
2663 client
->getName(), client
->getRegistryEntryID());
2669 victim
->__state
[1] |= kIOServiceTermPhase2State
;
2671 victim
->unlockForArbitration();
2675 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
2676 _workLoopAction( (IOWorkLoop::Action
) &actionWillStop
,
2677 victim
, (void *)(uintptr_t) options
, NULL
);
2680 OSArray
* notifiers
;
2681 notifiers
= victim
->copyNotifiers(gIOWillTerminateNotification
, 0, 0xffffffff);
2682 victim
->invokeNotifiers(¬ifiers
);
2684 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
2685 victim
, (void *)(uintptr_t) options
, (void *)(uintptr_t) doPhase2List
);
2687 didPhase2List
->headQ( victim
);
2690 victim
= (IOService
*) doPhase2List
->getObject(0);
2693 doPhase2List
->removeObject(0);
2697 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
2698 bool scheduleFinalize
= false;
2699 if( victim
->lockForArbitration( true )) {
2700 victim
->__state
[1] |= kIOServiceTermPhase3State
;
2701 scheduleFinalize
= (0 == victim
->getClient());
2702 victim
->unlockForArbitration();
2704 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
2705 victim
, (void *)(uintptr_t) options
);
2706 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
2707 _workLoopAction( (IOWorkLoop::Action
) &actionDidStop
,
2708 victim
, (void *)(uintptr_t) options
, NULL
);
2710 // no clients - will go to finalize
2711 if (scheduleFinalize
) victim
->scheduleFinalize(false);
2712 didPhase2List
->removeObject(0);
2714 IOLockLock( gJobsLock
);
2721 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
2722 bool sendFinal
= false;
2723 IOLockUnlock( gJobsLock
);
2724 if (victim
->lockForArbitration(true)) {
2725 sendFinal
= (0 == (victim
->__state
[1] & kIOServiceFinalized
));
2726 if (sendFinal
) victim
->__state
[1] |= kIOServiceFinalized
;
2727 victim
->unlockForArbitration();
2730 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
2731 victim
, (void *)(uintptr_t) options
);
2733 IOLockLock( gJobsLock
);
2735 freeList
->setObject( victim
);
2736 // safe if finalize list is append only
2737 gIOFinalizeList
->removeObject(0);
2741 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
2743 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
2746 uint64_t regID1
= provider
->getRegistryEntryID();
2747 uint64_t regID2
= client
->getRegistryEntryID();
2749 if( !provider
->isChild( client
, gIOServicePlane
)) {
2750 // may be multiply queued - nop it
2751 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2753 IOSERVICE_TERMINATE_STOP_NOP
,
2755 (uintptr_t) (regID1
>> 32),
2757 (uintptr_t) (regID2
>> 32));
2760 // a terminated client is not ready for stop if it has clients, skip it
2761 bool deferStop
= (0 != (kIOServiceInactiveState
& client
->__state
[0]));
2762 IOLockUnlock( gJobsLock
);
2763 if (deferStop
&& client
->lockForArbitration(true)) {
2764 deferStop
= (0 == (client
->__state
[1] & kIOServiceFinalized
));
2765 //deferStop = (!deferStop && (0 != client->getClient()));
2766 //deferStop = (0 != client->getClient());
2767 client
->unlockForArbitration();
2769 TLOG("%s[0x%qx]::defer stop()\n", client
->getName(), regID2
);
2770 IOServiceTrace(IOSERVICE_TERMINATE_STOP_DEFER
,
2772 (uintptr_t) (regID1
>> 32),
2774 (uintptr_t) (regID2
>> 32));
2777 IOLockLock( gJobsLock
);
2781 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
2782 provider
, (void *) client
);
2783 IOLockLock( gJobsLock
);
2784 // check the finalize list now
2788 freeList
->setObject( client
);
2789 freeList
->setObject( provider
);
2791 // safe if stop list is append only
2792 gIOStopList
->removeObject( idx
);
2793 gIOStopProviderList
->removeObject( idx
);
2797 } while( doPhase3
);
2799 gIOTerminateWork
-= workDone
;
2800 moreToDo
= (gIOTerminateWork
!= 0);
2803 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
2805 IOSERVICE_TERMINATE_DONE
,
2806 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
2809 } while( moreToDo
);
2811 IOLockUnlock( gJobsLock
);
2813 freeList
->release();
2814 doPhase2List
->release();
2815 didPhase2List
->release();
2817 IOLockLock( gJobsLock
);
2820 bool IOService::finalize( IOOptionBits options
)
2823 IOService
* provider
;
2824 uint64_t regID1
, regID2
= getRegistryEntryID();
2826 iter
= getProviderIterator();
2830 while( (provider
= (IOService
*) iter
->getNextObject())) {
2833 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2834 /* we come down here on programmatic terminate */
2836 regID1
= provider
->getRegistryEntryID();
2837 TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2
, provider
->getName(), regID1
);
2839 IOSERVICE_TERMINATE_STOP
,
2841 (uintptr_t) (regID1
>> 32),
2843 (uintptr_t) (regID2
>> 32));
2846 if( provider
->isOpen( this ))
2847 provider
->close( this );
2851 if( provider
->lockForArbitration( true )) {
2852 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2853 scheduleStop( provider
);
2854 provider
->unlockForArbitration();
2871 void IOService::doServiceTerminate( IOOptionBits options
)
2875 // a method in case someone needs to override it
2876 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2880 if( client
->isParent( this, gIOServicePlane
, true))
2881 // we are the clients only provider
2882 ok
= client
->terminate( options
);
2889 bool IOService::terminate( IOOptionBits options
)
2891 options
|= kIOServiceTerminate
;
2893 return( terminatePhase1( options
));
2896 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2902 struct ServiceOpenMessageContext
2904 IOService
* service
;
2906 IOService
* excludeClient
;
2907 IOOptionBits options
;
2910 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2912 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2914 if( object
!= context
->excludeClient
)
2915 context
->service
->messageClient( context
->type
, object
, (void *)(uintptr_t) context
->options
);
2918 bool IOService::open( IOService
* forClient
,
2919 IOOptionBits options
,
2923 ServiceOpenMessageContext context
;
2925 context
.service
= this;
2926 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2927 context
.excludeClient
= forClient
;
2928 context
.options
= options
;
2930 applyToInterested( gIOGeneralInterest
,
2931 &serviceOpenMessageApplier
, &context
);
2933 if( false == lockForArbitration(false) )
2936 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2938 ok
= handleOpen( forClient
, options
, arg
);
2940 unlockForArbitration();
2945 void IOService::close( IOService
* forClient
,
2946 IOOptionBits options
)
2951 lockForArbitration();
2953 wasClosed
= handleIsOpen( forClient
);
2955 handleClose( forClient
, options
);
2956 last
= (__state
[1] & kIOServiceTermPhase3State
);
2959 unlockForArbitration();
2962 forClient
->scheduleStop( this );
2964 else if( wasClosed
) {
2966 ServiceOpenMessageContext context
;
2968 context
.service
= this;
2969 context
.type
= kIOMessageServiceWasClosed
;
2970 context
.excludeClient
= forClient
;
2971 context
.options
= options
;
2973 applyToInterested( gIOGeneralInterest
,
2974 &serviceOpenMessageApplier
, &context
);
2978 bool IOService::isOpen( const IOService
* forClient
) const
2980 IOService
* self
= (IOService
*) this;
2983 self
->lockForArbitration();
2985 ok
= handleIsOpen( forClient
);
2987 self
->unlockForArbitration();
2992 bool IOService::handleOpen( IOService
* forClient
,
2993 IOOptionBits options
,
2998 ok
= (0 == __owner
);
3000 __owner
= forClient
;
3002 else if( options
& kIOServiceSeize
) {
3003 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
3004 __owner
, (void *)(uintptr_t) options
));
3005 if( ok
&& (0 == __owner
))
3006 __owner
= forClient
;
3013 void IOService::handleClose( IOService
* forClient
,
3014 IOOptionBits options
)
3016 if( __owner
== forClient
)
3020 bool IOService::handleIsOpen( const IOService
* forClient
) const
3023 return( __owner
== forClient
);
3025 return( __owner
!= forClient
);
3029 * Probing & starting
3031 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3033 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
3034 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
3042 val1
= obj1
->priority
;
3045 val2
= obj2
->priority
;
3047 return ( val1
- val2
);
3050 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
3052 OSDictionary
* dict
;
3053 IOService
* service
;
3054 _IOServiceNotifier
* notify
;
3055 OSSymbol
* key
= (OSSymbol
*) ref
;
3061 result
= kIODefaultProbeScore
;
3062 if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
3063 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
3064 else if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
3065 return( notify
->priority
);
3066 else if( (service
= OSDynamicCast( IOService
, entry
)))
3068 prop
= service
->copyProperty(key
);
3069 offset
= OSDynamicCast(OSNumber
, prop
);
3076 if (offset
) result
= offset
->unsigned32BitValue();
3078 OSSafeReleaseNULL(prop
);
3083 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3085 const OSObject
* obj1
= (const OSObject
*) inObj1
;
3086 const OSObject
* obj2
= (const OSObject
*) inObj2
;
3094 val1
= IOServiceObjectOrder( obj1
, ref
);
3097 val2
= IOServiceObjectOrder( obj2
, ref
);
3099 return ( val1
- val2
);
3102 IOService
* IOService::copyClientWithCategory( const OSSymbol
* category
)
3104 IOService
* service
= 0;
3106 const OSSymbol
* nextCat
;
3108 iter
= getClientIterator();
3110 while( (service
= (IOService
*) iter
->getNextObject())) {
3111 if( kIOServiceInactiveState
& service
->__state
[0])
3113 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
3114 service
->getProperty( gIOMatchCategoryKey
));
3115 if( category
== nextCat
)
3126 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
3129 service
= copyClientWithCategory(category
);
3135 bool IOService::invokeNotifier( _IOServiceNotifier
* notify
)
3137 _IOServiceNotifierInvocation invocation
;
3140 invocation
.thread
= current_thread();
3142 #if DEBUG_NOTIFIER_LOCKED
3144 if ((count
= isLockedForArbitration(0)))
3146 IOLog("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3147 panic("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3149 #endif /* DEBUG_NOTIFIER_LOCKED */
3152 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
3155 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
3156 _IOServiceNotifierInvocation
*, link
);
3162 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
3165 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
3166 _IOServiceNotifierInvocation
*, link
);
3167 if( kIOServiceNotifyWaiter
& notify
->state
) {
3168 notify
->state
&= ~kIOServiceNotifyWaiter
;
3169 WAKEUPNOTIFY( notify
);
3177 bool IOService::invokeNotifiers(OSArray
** willSend
)
3180 _IOServiceNotifier
* notify
;
3184 if (!array
) return (true);
3187 for( unsigned int idx
= 0;
3188 (notify
= (_IOServiceNotifier
*) array
->getObject(idx
));
3190 ret
&= invokeNotifier(notify
);
3199 * Alloc and probe matching classes,
3200 * called on the provider instance
3203 void IOService::probeCandidates( OSOrderedSet
* matches
)
3205 OSDictionary
* match
= 0;
3208 IOService
* newInst
;
3209 OSDictionary
* props
;
3212 OSOrderedSet
* familyMatches
= 0;
3213 OSOrderedSet
* startList
;
3214 OSDictionary
* startDict
= 0;
3215 const OSSymbol
* category
;
3217 _IOServiceNotifier
* notify
;
3218 OSObject
* nextMatch
= 0;
3220 bool needReloc
= false;
3224 IOService
* client
= NULL
;
3228 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
3230 nextMatch
->retain();
3231 matches
->removeObject(nextMatch
);
3233 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
3235 if (0 == (__state
[0] & kIOServiceInactiveState
)) invokeNotifier( notify
);
3236 nextMatch
->release();
3240 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
3241 nextMatch
->release();
3248 debugFlags
= getDebugFlags( match
);
3252 category
= OSDynamicCast( OSSymbol
,
3253 match
->getObject( gIOMatchCategoryKey
));
3255 category
= gIODefaultMatchCategoryKey
;
3257 if( (client
= copyClientWithCategory(category
)) ) {
3259 if( (debugFlags
& kIOLogMatch
) && (this != gIOResources
))
3260 LOG("%s: match category %s exists\n", getName(),
3261 category
->getCStringNoCopy());
3263 nextMatch
->release();
3272 // create a copy now in case its modified during matching
3273 props
= OSDictionary::withDictionary( match
, match
->getCount());
3276 props
->setCapacityIncrement(1);
3278 // check the nub matches
3279 if( false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
))
3282 // Check to see if driver reloc has been loaded.
3283 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
3286 if( debugFlags
& kIOLogCatalogue
)
3287 LOG("%s: stalling for module\n", getName());
3289 // If reloc hasn't been loaded, exit;
3290 // reprobing will occur after reloc has been loaded.
3294 // reorder on family matchPropertyTable score.
3295 if( 0 == familyMatches
)
3296 familyMatches
= OSOrderedSet::withCapacity( 1,
3297 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3299 familyMatches
->setObject( props
);
3304 nextMatch
->release();
3313 if( familyMatches
) {
3316 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
3319 familyMatches
->removeObject( props
);
3324 debugFlags
= getDebugFlags( props
);
3327 symbol
= OSDynamicCast( OSSymbol
,
3328 props
->getObject( gIOClassKey
));
3332 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), IOSERVICE_OBFUSCATE(symbol), IOSERVICE_OBFUSCATE(props));
3334 // alloc the driver instance
3335 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
3337 if( !inst
|| !OSDynamicCast(IOService
, inst
)) {
3338 IOLog("Couldn't alloc class \"%s\"\n",
3339 symbol
->getCStringNoCopy());
3343 // init driver instance
3344 if( !(inst
->init( props
))) {
3346 if( debugFlags
& kIOLogStart
)
3347 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
3351 if( __state
[1] & kIOServiceSynchronousState
)
3352 inst
->__state
[1] |= kIOServiceSynchronousState
;
3354 // give the driver the default match category if not specified
3355 category
= OSDynamicCast( OSSymbol
,
3356 props
->getObject( gIOMatchCategoryKey
));
3358 category
= gIODefaultMatchCategoryKey
;
3359 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
3360 // attach driver instance
3361 if( !(inst
->attach( this )))
3364 // pass in score from property table
3365 score
= familyMatches
->orderObject( props
);
3367 // & probe the new driver instance
3369 if( debugFlags
& kIOLogProbe
)
3370 LOG("%s::probe(%s)\n",
3371 inst
->getMetaClass()->getClassName(), getName());
3374 newInst
= inst
->probe( this, &score
);
3375 inst
->detach( this );
3378 if( debugFlags
& kIOLogProbe
)
3379 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
3385 newPri
= OSNumber::withNumber( score
, 32 );
3387 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
3391 // add to start list for the match category
3393 startDict
= OSDictionary::withCapacity( 1 );
3394 assert( startDict
);
3395 startList
= (OSOrderedSet
*)
3396 startDict
->getObject( category
);
3397 if( 0 == startList
) {
3398 startList
= OSOrderedSet::withCapacity( 1,
3399 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3400 if( startDict
&& startList
) {
3401 startDict
->setObject( category
, startList
);
3402 startList
->release();
3405 assert( startList
);
3407 startList
->setObject( newInst
);
3415 familyMatches
->release();
3419 // start the best (until success) of each category
3421 iter
= OSCollectionIterator::withCollection( startDict
);
3423 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
3425 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
3426 assert( startList
);
3431 while( true // (!started)
3432 && (inst
= (IOService
*)startList
->getFirstObject())) {
3435 startList
->removeObject(inst
);
3438 debugFlags
= getDebugFlags( inst
);
3440 if( debugFlags
& kIOLogStart
) {
3442 LOG( "match category exists, skipping " );
3443 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
3444 getName(), inst
->getRetainCount());
3447 if( false == started
)
3448 started
= startCandidate( inst
);
3450 if( (debugFlags
& kIOLogStart
) && (false == started
))
3451 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
3452 inst
->getRetainCount());
3461 // adjust the busy count by +1 if matching is stalled for a module,
3462 // or -1 if a previously stalled matching is complete.
3463 lockForArbitration();
3465 uint64_t regID
= getRegistryEntryID();
3468 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
3472 IOSERVICE_MODULESTALL
,
3474 (uintptr_t) (regID
>> 32),
3478 __state
[1] |= kIOServiceModuleStallState
;
3481 } else if( __state
[1] & kIOServiceModuleStallState
) {
3484 IOSERVICE_MODULEUNSTALL
,
3486 (uintptr_t) (regID
>> 32),
3490 __state
[1] &= ~kIOServiceModuleStallState
;
3494 _adjustBusy( adjBusy
);
3495 unlockForArbitration();
3498 startDict
->release();
3502 * Start a previously attached & probed instance,
3503 * called on exporting object instance
3506 bool IOService::startCandidate( IOService
* service
)
3510 ok
= service
->attach( this );
3514 if (this != gIOResources
)
3516 // stall for any nub resources
3518 // stall for any driver resources
3519 service
->checkResources();
3522 AbsoluteTime startTime
;
3523 AbsoluteTime endTime
;
3526 if (kIOLogStart
& gIOKitDebug
)
3527 clock_get_uptime(&startTime
);
3529 ok
= service
->start(this);
3531 if (kIOLogStart
& gIOKitDebug
)
3533 clock_get_uptime(&endTime
);
3535 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
3537 SUB_ABSOLUTETIME(&endTime
, &startTime
);
3538 absolutetime_to_nanoseconds(endTime
, &nano
);
3539 if (nano
> 500000000ULL)
3540 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
3544 service
->detach( this );
3549 void IOService::publishResource( const char * key
, OSObject
* value
)
3551 const OSSymbol
* sym
;
3553 if( (sym
= OSSymbol::withCString( key
))) {
3554 publishResource( sym
, value
);
3559 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
3562 value
= (OSObject
*) gIOServiceKey
;
3564 gIOResources
->setProperty( key
, value
);
3566 if( IORecursiveLockHaveLock( gNotificationLock
))
3569 gIOResourceGenerationCount
++;
3570 gIOResources
->registerService();
3573 bool IOService::addNeededResource( const char * key
)
3575 OSObject
* resourcesProp
;
3580 resourcesProp
= copyProperty( gIOResourceMatchKey
);
3581 if (!resourcesProp
) return(false);
3583 newKey
= OSString::withCString( key
);
3586 resourcesProp
->release();
3590 set
= OSDynamicCast( OSSet
, resourcesProp
);
3592 set
= OSSet::withCapacity( 1 );
3594 set
->setObject( resourcesProp
);
3599 set
->setObject( newKey
);
3601 ret
= setProperty( gIOResourceMatchKey
, set
);
3603 resourcesProp
->release();
3608 bool IOService::checkResource( OSObject
* matching
)
3611 OSDictionary
* table
;
3613 if( (str
= OSDynamicCast( OSString
, matching
))) {
3614 if( gIOResources
->getProperty( str
))
3619 table
= resourceMatching( str
);
3620 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
3623 IOLog("%s: Can't match using: %s\n", getName(),
3624 matching
->getMetaClass()->getClassName());
3625 /* false would stall forever */
3629 if( gIOKitDebug
& kIOLogConfig
)
3630 LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName());
3632 waitForService( table
);
3634 if( gIOKitDebug
& kIOLogConfig
)
3635 LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()) );
3640 bool IOService::checkResources( void )
3642 OSObject
* resourcesProp
;
3647 resourcesProp
= copyProperty( gIOResourceMatchKey
);
3648 if( 0 == resourcesProp
)
3651 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
3653 iter
= OSCollectionIterator::withCollection( set
);
3655 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
3656 ok
= checkResource( resourcesProp
);
3661 ok
= checkResource( resourcesProp
);
3663 OSSafeReleaseNULL(resourcesProp
);
3669 void _IOConfigThread::configThread( void )
3671 _IOConfigThread
* inst
;
3674 if( !(inst
= new _IOConfigThread
))
3679 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &unused
))
3692 void _IOConfigThread::free( void )
3694 thread_deallocate(current_thread());
3698 void IOService::doServiceMatch( IOOptionBits options
)
3700 _IOServiceNotifier
* notify
;
3702 OSOrderedSet
* matches
;
3703 OSArray
* resourceKeys
= 0;
3704 SInt32 catalogGeneration
;
3705 bool keepGuessing
= true;
3706 bool reRegistered
= true;
3708 OSArray
* notifiers
[2] = {0};
3710 // job->nub->deliverNotification( gIOPublishNotification,
3711 // kIOServiceRegisteredState, 0xffffffff );
3713 while( keepGuessing
) {
3715 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
3716 // the matches list should always be created by findDrivers()
3719 lockForArbitration();
3720 if( 0 == (__state
[0] & kIOServiceFirstPublishState
)) {
3721 getMetaClass()->addInstance(this);
3722 notifiers
[0] = copyNotifiers(gIOFirstPublishNotification
,
3723 kIOServiceFirstPublishState
, 0xffffffff );
3726 __state
[1] &= ~kIOServiceNeedConfigState
;
3727 __state
[1] |= kIOServiceConfigState
| kIOServiceConfigRunning
;
3728 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
3729 __state
[0] |= kIOServiceRegisteredState
;
3731 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
3732 if (reRegistered
&& keepGuessing
) {
3733 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3734 gNotifications
->getObject( gIOPublishNotification
) );
3736 while((notify
= (_IOServiceNotifier
*)
3737 iter
->getNextObject())) {
3739 if( matchPassive(notify
->matching
, 0)
3740 && (kIOServiceNotifyEnable
& notify
->state
))
3741 matches
->setObject( notify
);
3748 unlockForArbitration();
3749 invokeNotifiers(¬ifiers
[0]);
3751 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources()))
3753 if (this == gIOResources
)
3755 if (resourceKeys
) resourceKeys
->release();
3756 resourceKeys
= copyPropertyKeys();
3758 probeCandidates( matches
);
3764 lockForArbitration();
3765 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
3767 (reRegistered
|| (catalogGeneration
!=
3768 gIOCatalogue
->getGenerationCount()))
3769 && (0 == (__state
[0] & kIOServiceInactiveState
));
3772 unlockForArbitration();
3775 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3776 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
3778 if (resourceKeys
) setProperty(gIOResourceMatchedKey
, resourceKeys
);
3780 notifiers
[0] = copyNotifiers(gIOMatchedNotification
,
3781 kIOServiceMatchedState
, 0xffffffff);
3782 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
3783 notifiers
[1] = copyNotifiers(gIOFirstMatchNotification
,
3784 kIOServiceFirstMatchState
, 0xffffffff);
3787 __state
[1] &= ~kIOServiceConfigRunning
;
3788 unlockForArbitration();
3790 if (resourceKeys
) resourceKeys
->release();
3792 invokeNotifiers(¬ifiers
[0]);
3793 invokeNotifiers(¬ifiers
[1]);
3795 lockForArbitration();
3796 __state
[1] &= ~kIOServiceConfigState
;
3797 scheduleTerminatePhase2();
3800 unlockForArbitration();
3803 UInt32
IOService::_adjustBusy( SInt32 delta
)
3808 bool wasQuiet
, nowQuiet
, needWake
;
3811 result
= __state
[1] & kIOServiceBusyStateMask
;
3815 next
->lockForArbitration();
3816 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
3817 wasQuiet
= (0 == count
);
3818 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
)))
3819 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
3822 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
3823 nowQuiet
= (0 == count
);
3824 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
3827 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
3828 IOLockLock( gIOServiceBusyLock
);
3829 thread_wakeup( (event_t
) next
);
3830 IOLockUnlock( gIOServiceBusyLock
);
3833 next
->unlockForArbitration();
3835 if( (wasQuiet
|| nowQuiet
) ) {
3837 uint64_t regID
= next
->getRegistryEntryID();
3839 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
3841 (uintptr_t) (regID
>> 32),
3847 next
->__timeBusy
= mach_absolute_time();
3851 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
3852 next
->__timeBusy
= 0;
3855 MessageClientsContext context
;
3857 context
.service
= next
;
3858 context
.type
= kIOMessageServiceBusyStateChange
;
3859 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
3860 context
.argSize
= 0;
3862 applyToInterestNotifiers( next
, gIOBusyInterest
,
3863 &messageClientsApplier
, &context
);
3866 if( nowQuiet
&& (next
== gIOServiceRoot
)) {
3867 OSKext::considerUnloads();
3868 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
3873 delta
= nowQuiet
? -1 : +1;
3875 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
3880 void IOService::adjustBusy( SInt32 delta
)
3882 lockForArbitration();
3883 _adjustBusy( delta
);
3884 unlockForArbitration();
3887 uint64_t IOService::getAccumulatedBusyTime( void )
3889 uint64_t accumBusy
= __accumBusy
;
3890 uint64_t timeBusy
= __timeBusy
;
3895 accumBusy
= __accumBusy
;
3896 timeBusy
= __timeBusy
;
3898 accumBusy
+= mach_absolute_time() - timeBusy
;
3900 while (timeBusy
!= __timeBusy
);
3902 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
3907 UInt32
IOService::getBusyState( void )
3909 return( __state
[1] & kIOServiceBusyStateMask
);
3912 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3913 mach_timespec_t
* timeout
)
3915 panic("waitForState");
3916 return (kIOReturnUnsupported
);
3919 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3923 int waitResult
= THREAD_AWAKENED
;
3924 bool computeDeadline
= true;
3925 AbsoluteTime abstime
;
3928 lockForArbitration();
3929 IOLockLock( gIOServiceBusyLock
);
3930 wait
= (value
!= (__state
[1] & mask
));
3932 __state
[1] |= kIOServiceBusyWaiterState
;
3933 unlockForArbitration();
3934 if( timeout
!= UINT64_MAX
) {
3935 if( computeDeadline
) {
3936 AbsoluteTime nsinterval
;
3937 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
3938 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
3939 computeDeadline
= false;
3941 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
3944 assert_wait((event_t
)this, THREAD_UNINT
);
3946 unlockForArbitration();
3947 IOLockUnlock( gIOServiceBusyLock
);
3949 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
3951 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3953 if( waitResult
== THREAD_TIMED_OUT
)
3954 return( kIOReturnTimeout
);
3956 return( kIOReturnSuccess
);
3959 IOReturn
IOService::waitQuiet( uint64_t timeout
)
3963 char * string
= NULL
;
3964 char * panicString
= NULL
;
3966 size_t panicStringLen
;
3972 enum { kTimeoutExtensions
= 4 };
3974 time
= mach_absolute_time();
3976 for (loops
= 0; loops
< kTimeoutExtensions
; loops
++)
3978 ret
= waitForState( kIOServiceBusyStateMask
, 0, timeout
);
3980 if (loops
&& (kIOReturnSuccess
== ret
))
3982 time
= mach_absolute_time() - time
;
3983 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&time
, &nano
);
3984 IOLog("busy extended ok[%d], (%llds, %llds)\n",
3985 loops
, timeout
/ 1000000000ULL, nano
/ 1000000000ULL);
3988 else if (kIOReturnTimeout
!= ret
) break;
3989 else if (timeout
< 41000000000) break;
3992 IORegistryIterator
* iter
;
3994 OSOrderedSet
* leaves
;
3996 IOService
* nextParent
;
4001 panicStringLen
= 256;
4002 if (!string
) string
= IONew(char, len
);
4003 if (!panicString
) panicString
= IONew(char, panicStringLen
);
4005 kextdWait
= OSKext::isWaitingKextd();
4006 iter
= IORegistryIterator::iterateOver(this, gIOServicePlane
, kIORegistryIterateRecursively
);
4007 leaves
= OSOrderedSet::withCapacity(4);
4008 if (iter
) set
= iter
->iterateAll();
4009 if (string
&& panicString
&& leaves
&& set
)
4011 string
[0] = panicString
[0] = 0;
4012 set
->setObject(this);
4013 while ((next
= (IOService
*) set
->getLastObject()))
4015 if (next
->getBusyState())
4017 if (kIOServiceModuleStallState
& next
->__state
[1]) kextdWait
= true;
4018 leaves
->setObject(next
);
4020 while ((nextParent
= nextParent
->getProvider()))
4022 set
->removeObject(nextParent
);
4023 leaves
->removeObject(nextParent
);
4026 set
->removeObject(next
);
4029 while ((next
= (IOService
*) leaves
->getLastObject()))
4031 l
= snprintf(s
, len
, "%s'%s'", ((s
== string
) ? "" : ", "), next
->getName());
4032 if (l
>= len
) break;
4035 leaves
->removeObject(next
);
4038 OSSafeReleaseNULL(leaves
);
4039 OSSafeReleaseNULL(set
);
4040 OSSafeReleaseNULL(iter
);
4043 dopanic
= ((loops
>= (kTimeoutExtensions
- 1)) && (kIOWaitQuietPanics
& gIOKitDebug
));
4044 snprintf(panicString
, panicStringLen
,
4045 "%s[%d], (%llds): %s",
4046 kextdWait
? "kextd stall" : "busy timeout",
4047 loops
, timeout
/ 1000000000ULL,
4048 string
? string
: "");
4049 IOLog("%s\n", panicString
);
4050 if (dopanic
) panic("%s", panicString
);
4051 else if (!loops
) getPMRootDomain()->startSpinDump(1);
4054 if (string
) IODelete(string
, char, 256);
4055 if (panicString
) IODelete(panicString
, char, panicStringLen
);
4060 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
4066 timeoutNS
= timeout
->tv_sec
;
4067 timeoutNS
*= kSecondScale
;
4068 timeoutNS
+= timeout
->tv_nsec
;
4071 timeoutNS
= UINT64_MAX
;
4073 return (waitQuiet(timeoutNS
));
4076 bool IOService::serializeProperties( OSSerialize
* s
) const
4079 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
4080 sizeof( __state
), "__state");
4082 return( super::serializeProperties(s
) );
4086 void _IOConfigThread::main(void * arg
, wait_result_t result
)
4088 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
4089 _IOServiceJob
* job
;
4093 thread_precedence_policy_data_t precedence
= { -1 };
4095 kr
= thread_policy_set(current_thread(),
4096 THREAD_PRECEDENCE_POLICY
,
4097 (thread_policy_t
) &precedence
,
4098 THREAD_PRECEDENCE_POLICY_COUNT
);
4099 if (KERN_SUCCESS
!= kr
)
4100 IOLog("thread_policy_set(%d)\n", kr
);
4106 semaphore_wait( gJobsSemaphore
);
4108 IOTakeLock( gJobsLock
);
4109 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
4111 gJobs
->removeObject(job
);
4114 // gNumConfigThreads--; // we're out of service
4115 gNumWaitingThreads
--; // we're out of service
4117 IOUnlock( gJobsLock
);
4123 if( gIOKitDebug
& kIOLogConfig
)
4124 LOG("config(%p): starting on %s, %d\n",
4125 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->nub
->getName(), job
->type
);
4127 switch( job
->type
) {
4130 nub
->doServiceMatch( job
->options
);
4134 LOG("config(%p): strange type (%d)\n",
4135 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->type
);
4142 IOTakeLock( gJobsLock
);
4143 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
4145 gNumWaitingThreads
++; // back in service
4146 // gNumConfigThreads++;
4148 if( 0 == --gNumConfigThreads
) {
4149 // IOLog("MATCH IDLE\n");
4150 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
4153 IOUnlock( gJobsLock
);
4158 if( gIOKitDebug
& kIOLogConfig
)
4159 LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()) );
4164 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
4167 int waitResult
= THREAD_AWAKENED
;
4168 bool computeDeadline
= true;
4169 AbsoluteTime deadline
;
4171 IOLockLock( gJobsLock
);
4173 wait
= (0 != gNumConfigThreads
);
4176 if( computeDeadline
) {
4177 clock_interval_to_deadline(
4178 msToWait
, kMillisecondScale
, &deadline
);
4179 computeDeadline
= false;
4181 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
4182 deadline
, THREAD_UNINT
);
4184 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
4188 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
4189 IOLockUnlock( gJobsLock
);
4191 if( waitResult
== THREAD_TIMED_OUT
)
4192 return( kIOReturnTimeout
);
4194 return( kIOReturnSuccess
);
4197 void IOService::cpusRunning(void)
4199 gCPUsRunning
= true;
4202 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
4209 IOTakeLock( gJobsLock
);
4212 gJobs
->setLastObject( job
);
4214 count
= gNumWaitingThreads
;
4215 // if( gNumConfigThreads) count++;// assume we're called from a config thread
4217 create
= ( (gOutstandingJobs
> count
)
4218 && ((gNumConfigThreads
< kMaxConfigThreads
)
4219 || (job
->nub
== gIOResources
)
4222 gNumConfigThreads
++;
4223 gNumWaitingThreads
++;
4226 IOUnlock( gJobsLock
);
4231 if( gIOKitDebug
& kIOLogConfig
)
4232 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
4233 _IOConfigThread::configThread();
4236 semaphore_signal( gJobsSemaphore
);
4239 struct IOServiceMatchContext
4241 OSDictionary
* table
;
4249 bool IOService::instanceMatch(const OSObject
* entry
, void * context
)
4251 IOServiceMatchContext
* ctx
= (typeof(ctx
)) context
;
4252 IOService
* service
= (typeof(service
)) entry
;
4253 OSDictionary
* table
= ctx
->table
;
4254 uint32_t options
= ctx
->options
;
4255 uint32_t state
= ctx
->state
;
4262 match
= ((state
== (state
& service
->__state
[0]))
4263 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
4265 ctx
->count
+= table
->getCount();
4266 match
= service
->matchInternal(table
, options
, &done
);
4273 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
))
4276 ctx
->result
= service
;
4279 else if (!ctx
->result
)
4281 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
4285 ((OSSet
*)ctx
->result
)->setObject(service
);
4290 // internal - call with gNotificationLock
4291 OSObject
* IOService::copyExistingServices( OSDictionary
* matching
,
4292 IOOptionBits inState
, IOOptionBits options
)
4294 OSObject
* current
= 0;
4296 IOService
* service
;
4304 OSSerialize
* s
= OSSerialize::withCapacity(128);
4305 matching
->serialize(s
);
4308 if((obj
= matching
->getObject(gIOProviderClassKey
))
4310 && gIOResourcesKey
->isEqualTo(obj
)
4311 && (service
= gIOResources
))
4313 if( (inState
== (service
->__state
[0] & inState
))
4314 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
4315 && service
->matchPassive(matching
, options
))
4317 if( options
& kIONotifyOnce
)
4323 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
4328 IOServiceMatchContext ctx
;
4329 ctx
.table
= matching
;
4330 ctx
.state
= inState
;
4333 ctx
.options
= options
;
4336 if ((str
= OSDynamicCast(OSString
, obj
)))
4338 const OSSymbol
* sym
= OSSymbol::withString(str
);
4339 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
4344 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
4348 current
= ctx
.result
;
4350 options
|= kIOServiceInternalDone
| kIOServiceClassDone
;
4351 if (current
&& (ctx
.done
!= ctx
.count
))
4354 source
= OSDynamicCast(OSSet
, current
);
4356 while ((service
= (IOService
*) source
->getAnyObject()))
4358 if (service
->matchPassive(matching
, options
))
4360 if( options
& kIONotifyOnce
)
4368 ((OSSet
*)current
)->setObject( service
);
4372 current
= OSSet::withObjects(
4373 (const OSObject
**) &service
, 1, 1 );
4376 source
->removeObject(service
);
4384 OSObject
* _current
= 0;
4386 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
4387 kIORegistryIterateRecursively
);
4391 while( (service
= (IOService
*) iter
->getNextObject())) {
4392 if( (inState
== (service
->__state
[0] & inState
))
4393 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
4394 && service
->matchPassive(matching
, 0)) {
4396 if( options
& kIONotifyOnce
) {
4402 ((OSSet
*)_current
)->setObject( service
);
4404 _current
= OSSet::withObjects(
4405 (const OSObject
**) &service
, 1, 1 );
4408 } while( !service
&& !iter
->isValid());
4413 if ( ((current
!= 0) != (_current
!= 0))
4414 || (current
&& _current
&& !current
->isEqualTo(_current
)))
4416 OSSerialize
* s1
= OSSerialize::withCapacity(128);
4417 OSSerialize
* s2
= OSSerialize::withCapacity(128);
4418 current
->serialize(s1
);
4419 _current
->serialize(s2
);
4420 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current
),
4421 IOSERVICE_OBFUSCATE(_current
), s
->text(), s1
->text(), s2
->text());
4426 if (_current
) _current
->release();
4432 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
4433 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
4442 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
4446 // is a lock even needed?
4449 iter
= (OSIterator
*) copyExistingServices( matching
,
4450 kIOServiceMatchedState
);
4457 IOService
* IOService::copyMatchingService( OSDictionary
* matching
)
4459 IOService
* service
;
4461 // is a lock even needed?
4464 service
= (IOService
*) copyExistingServices( matching
,
4465 kIOServiceMatchedState
, kIONotifyOnce
);
4472 struct _IOServiceMatchingNotificationHandlerRef
4474 IOServiceNotificationHandler handler
;
4478 static bool _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
4479 IOService
* newService
,
4480 IONotifier
* notifier
)
4482 return ((*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
));
4485 // internal - call with gNotificationLock
4486 IONotifier
* IOService::setNotification(
4487 const OSSymbol
* type
, OSDictionary
* matching
,
4488 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
4491 _IOServiceNotifier
* notify
= 0;
4497 notify
= new _IOServiceNotifier
;
4498 if( notify
&& !notify
->init()) {
4504 notify
->handler
= handler
;
4505 notify
->target
= target
;
4506 notify
->type
= type
;
4507 notify
->matching
= matching
;
4509 if (handler
== &_IOServiceMatchingNotificationHandler
)
4511 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
4512 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
4516 notify
->priority
= priority
;
4517 notify
->state
= kIOServiceNotifyEnable
;
4518 queue_init( ¬ify
->handlerInvocations
);
4522 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
4523 set
= OSOrderedSet::withCapacity( 1,
4524 IONotifyOrdering
, 0 );
4526 gNotifications
->setObject( type
, set
);
4530 notify
->whence
= set
;
4532 set
->setObject( notify
);
4538 // internal - call with gNotificationLock
4539 IONotifier
* IOService::doInstallNotification(
4540 const OSSymbol
* type
, OSDictionary
* matching
,
4541 IOServiceMatchingNotificationHandler handler
,
4542 void * target
, void * ref
,
4543 SInt32 priority
, OSIterator
** existing
)
4546 IONotifier
* notify
;
4547 IOOptionBits inState
;
4552 if( type
== gIOPublishNotification
)
4553 inState
= kIOServiceRegisteredState
;
4555 else if( type
== gIOFirstPublishNotification
)
4556 inState
= kIOServiceFirstPublishState
;
4558 else if (type
== gIOMatchedNotification
)
4559 inState
= kIOServiceMatchedState
;
4561 else if (type
== gIOFirstMatchNotification
)
4562 inState
= kIOServiceFirstMatchState
;
4564 else if ((type
== gIOTerminatedNotification
) || (type
== gIOWillTerminateNotification
))
4569 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
4572 // get the current set
4573 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
4582 #if !defined(__LP64__)
4583 IONotifier
* IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
4584 IOServiceNotificationHandler handler
,
4585 void * target
, void * refCon
,
4586 SInt32 priority
, OSIterator
** existing
)
4588 IONotifier
* result
;
4589 _IOServiceMatchingNotificationHandlerRef ref
;
4590 ref
.handler
= handler
;
4593 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
4594 &_IOServiceMatchingNotificationHandler
,
4595 target
, &ref
, priority
, existing
);
4597 matching
->release();
4601 #endif /* !defined(__LP64__) */
4604 IONotifier
* IOService::installNotification(
4605 const OSSymbol
* type
, OSDictionary
* matching
,
4606 IOServiceMatchingNotificationHandler handler
,
4607 void * target
, void * ref
,
4608 SInt32 priority
, OSIterator
** existing
)
4610 IONotifier
* notify
;
4614 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
4615 priority
, existing
);
4617 // in case handler remove()s
4618 if (notify
) notify
->retain();
4625 IONotifier
* IOService::addNotification(
4626 const OSSymbol
* type
, OSDictionary
* matching
,
4627 IOServiceNotificationHandler handler
,
4628 void * target
, void * refCon
,
4631 IONotifier
* result
;
4632 _IOServiceMatchingNotificationHandlerRef ref
;
4634 ref
.handler
= handler
;
4637 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
4638 target
, &ref
, priority
);
4641 matching
->release();
4646 IONotifier
* IOService::addMatchingNotification(
4647 const OSSymbol
* type
, OSDictionary
* matching
,
4648 IOServiceMatchingNotificationHandler handler
,
4649 void * target
, void * ref
,
4652 OSIterator
* existing
= NULL
;
4654 _IOServiceNotifier
* notify
;
4657 ret
= notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
4658 handler
, target
, ref
, priority
, &existing
);
4659 if (!ret
) return (0);
4661 // send notifications for existing set
4664 while( (next
= (IOService
*) existing
->getNextObject()))
4666 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
4668 next
->invokeNotifier( notify
);
4671 existing
->release();
4675 bool removed
= (0 == notify
->whence
);
4677 if (removed
) ret
= gIOServiceNullNotifier
;
4683 bool IOService::syncNotificationHandler(
4684 void * /* target */, void * ref
,
4685 IOService
* newService
,
4686 IONotifier
* notifier
)
4690 if (!*((IOService
**) ref
))
4692 newService
->retain();
4693 (*(IOService
**) ref
) = newService
;
4701 IOService
* IOService::waitForMatchingService( OSDictionary
* matching
,
4704 IONotifier
* notify
= 0;
4705 // priority doesn't help us much since we need a thread wakeup
4706 SInt32 priority
= 0;
4717 result
= (IOService
*) copyExistingServices( matching
,
4718 kIOServiceMatchedState
, kIONotifyOnce
);
4721 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
4722 &IOService::syncNotificationHandler
, (void *) 0,
4723 &result
, priority
);
4726 if (UINT64_MAX
!= timeout
)
4728 AbsoluteTime deadline
;
4729 nanoseconds_to_absolutetime(timeout
, &deadline
);
4730 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
4731 SLEEPNOTIFYTO(&result
, deadline
);
4735 SLEEPNOTIFY(&result
);
4743 notify
->remove(); // dequeues
4748 IOService
* IOService::waitForService( OSDictionary
* matching
,
4749 mach_timespec_t
* timeout
)
4756 timeoutNS
= timeout
->tv_sec
;
4757 timeoutNS
*= kSecondScale
;
4758 timeoutNS
+= timeout
->tv_nsec
;
4761 timeoutNS
= UINT64_MAX
;
4763 result
= waitForMatchingService(matching
, timeoutNS
);
4765 matching
->release();
4772 void IOService::deliverNotification( const OSSymbol
* type
,
4773 IOOptionBits orNewState
, IOOptionBits andNewState
)
4775 panic("deliverNotification");
4778 OSArray
* IOService::copyNotifiers(const OSSymbol
* type
,
4779 IOOptionBits orNewState
, IOOptionBits andNewState
)
4781 _IOServiceNotifier
* notify
;
4783 OSArray
* willSend
= 0;
4785 lockForArbitration();
4787 if( (0 == (__state
[0] & kIOServiceInactiveState
))
4788 || (type
== gIOTerminatedNotification
)
4789 || (type
== gIOWillTerminateNotification
)) {
4793 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
4794 gNotifications
->getObject( type
) );
4797 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
4799 if( matchPassive(notify
->matching
, 0)
4800 && (kIOServiceNotifyEnable
& notify
->state
)) {
4802 willSend
= OSArray::withCapacity(8);
4804 willSend
->setObject( notify
);
4809 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
4813 unlockForArbitration();
4819 IOOptionBits
IOService::getState( void ) const
4821 return( __state
[0] );
4825 * Helpers to make matching objects for simple cases
4828 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
4829 OSDictionary
* table
)
4832 const OSString
* str
;
4834 str
= OSSymbol::withString(name
);
4839 table
= OSDictionary::withCapacity( 2 );
4841 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
4847 OSDictionary
* IOService::serviceMatching( const char * name
,
4848 OSDictionary
* table
)
4850 const OSString
* str
;
4852 str
= OSSymbol::withCString( name
);
4856 table
= serviceMatching( str
, table
);
4861 OSDictionary
* IOService::nameMatching( const OSString
* name
,
4862 OSDictionary
* table
)
4865 table
= OSDictionary::withCapacity( 2 );
4867 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
4872 OSDictionary
* IOService::nameMatching( const char * name
,
4873 OSDictionary
* table
)
4875 const OSString
* str
;
4877 str
= OSSymbol::withCString( name
);
4881 table
= nameMatching( str
, table
);
4886 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
4887 OSDictionary
* table
)
4889 table
= serviceMatching( gIOResourcesKey
, table
);
4891 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
4896 OSDictionary
* IOService::resourceMatching( const char * name
,
4897 OSDictionary
* table
)
4899 const OSSymbol
* str
;
4901 str
= OSSymbol::withCString( name
);
4905 table
= resourceMatching( str
, table
);
4911 OSDictionary
* IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
4912 OSDictionary
* table
)
4914 OSDictionary
* properties
;
4916 properties
= OSDictionary::withCapacity( 2 );
4919 properties
->setObject( key
, value
);
4922 table
= OSDictionary::withCapacity( 2 );
4924 table
->setObject( gIOPropertyMatchKey
, properties
);
4926 properties
->release();
4931 OSDictionary
* IOService::registryEntryIDMatching( uint64_t entryID
,
4932 OSDictionary
* table
)
4936 num
= OSNumber::withNumber( entryID
, 64 );
4941 table
= OSDictionary::withCapacity( 2 );
4943 table
->setObject( gIORegistryEntryIDKey
, num
);
4953 * _IOServiceNotifier
4956 // wait for all threads, other than the current one,
4957 // to exit the handler
4959 void _IOServiceNotifier::wait()
4961 _IOServiceNotifierInvocation
* next
;
4966 queue_iterate( &handlerInvocations
, next
,
4967 _IOServiceNotifierInvocation
*, link
) {
4968 if( next
->thread
!= current_thread() ) {
4974 state
|= kIOServiceNotifyWaiter
;
4981 void _IOServiceNotifier::free()
4983 assert( queue_empty( &handlerInvocations
));
4987 void _IOServiceNotifier::remove()
4992 whence
->removeObject( (OSObject
*) this );
4996 matching
->release();
5000 state
&= ~kIOServiceNotifyEnable
;
5009 bool _IOServiceNotifier::disable()
5015 ret
= (0 != (kIOServiceNotifyEnable
& state
));
5016 state
&= ~kIOServiceNotifyEnable
;
5025 void _IOServiceNotifier::enable( bool was
)
5029 state
|= kIOServiceNotifyEnable
;
5031 state
&= ~kIOServiceNotifyEnable
;
5037 * _IOServiceNullNotifier
5040 void _IOServiceNullNotifier::taggedRetain(const void *tag
) const {}
5041 void _IOServiceNullNotifier::taggedRelease(const void *tag
, const int when
) const {}
5042 void _IOServiceNullNotifier::free() {}
5043 void _IOServiceNullNotifier::wait() {}
5044 void _IOServiceNullNotifier::remove() {}
5045 void _IOServiceNullNotifier::enable(bool was
) {}
5046 bool _IOServiceNullNotifier::disable() { return(false); }
5052 IOService
* IOResources::resources( void )
5056 inst
= new IOResources
;
5057 if( inst
&& !inst
->init()) {
5065 bool IOResources::init( OSDictionary
* dictionary
)
5067 // Do super init first
5068 if ( !IOService::init() )
5071 // Allow PAL layer to publish a value
5072 const char *property_name
;
5075 pal_get_resource_property( &property_name
, &property_value
);
5077 if( property_name
) {
5079 const OSSymbol
* sym
;
5081 if( (num
= OSNumber::withNumber(property_value
, 32)) != 0 ) {
5082 if( (sym
= OSSymbol::withCString( property_name
)) != 0 ) {
5083 this->setProperty( sym
, num
);
5093 IOReturn
IOResources::newUserClient(task_t owningTask
, void * securityID
,
5094 UInt32 type
, OSDictionary
* properties
,
5095 IOUserClient
** handler
)
5097 return( kIOReturnUnsupported
);
5100 IOWorkLoop
* IOResources::getWorkLoop() const
5102 // If we are the resource root
5103 // then use the platform's workloop
5104 if (this == (IOResources
*) gIOResources
)
5105 return getPlatform()->getWorkLoop();
5107 return IOService::getWorkLoop();
5110 bool IOResources::matchPropertyTable( OSDictionary
* table
)
5120 prop
= table
->getObject( gIOResourceMatchKey
);
5121 str
= OSDynamicCast( OSString
, prop
);
5123 ok
= (0 != getProperty( str
));
5125 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
5127 iter
= OSCollectionIterator::withCollection( set
);
5129 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
5130 ok
= (0 != getProperty( str
));
5135 else if ((prop
= table
->getObject(gIOResourceMatchedKey
)))
5137 obj
= copyProperty(gIOResourceMatchedKey
);
5138 keys
= OSDynamicCast(OSArray
, obj
);
5142 // assuming OSSymbol
5143 ok
= ((-1U) != keys
->getNextIndexOfObject(prop
, 0));
5145 OSSafeReleaseNULL(obj
);
5151 void IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
5153 IOService::updateConsoleUsers(NULL
, 0);
5156 void IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
)
5158 IORegistryEntry
* regEntry
;
5159 OSObject
* locked
= kOSBooleanFalse
;
5162 OSDictionary
* user
;
5163 static IOMessage sSystemPower
;
5164 clock_sec_t now
= 0;
5165 clock_usec_t microsecs
;
5167 regEntry
= IORegistryEntry::getRegistryRoot();
5169 if (!gIOChosenEntry
)
5170 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
5172 IOLockLock(gIOConsoleUsersLock
);
5176 sSystemPower
= systemMessage
;
5178 if (kIOMessageSystemHasPoweredOn
== systemMessage
)
5180 uint32_t lockState
= IOHibernateWasScreenLocked();
5185 case kIOScreenLockLocked
:
5186 case kIOScreenLockFileVaultDialog
:
5187 gIOConsoleBooterLockState
= kOSBooleanTrue
;
5189 case kIOScreenLockNoLock
:
5190 gIOConsoleBooterLockState
= 0;
5192 case kIOScreenLockUnlocked
:
5194 gIOConsoleBooterLockState
= kOSBooleanFalse
;
5198 #endif /* HIBERNATION */
5204 bool loginLocked
= true;
5206 gIOConsoleLoggedIn
= false;
5208 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
5211 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
5212 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
5214 loginLocked
&= (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionScreenIsLockedKey
));
5217 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
5221 if (!loginLocked
) gIOConsoleBooterLockState
= 0;
5222 IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
5223 (num
!= 0), gIOConsoleLockTime
, (num
? num
->unsigned32BitValue() : 0),
5224 gIOConsoleLoggedIn
, loginLocked
);
5225 #endif /* HIBERNATION */
5226 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
5229 if (!gIOConsoleLoggedIn
5230 || (kIOMessageSystemWillSleep
== sSystemPower
)
5231 || (kIOMessageSystemPagingOff
== sSystemPower
))
5233 locked
= kOSBooleanTrue
;
5236 else if (gIOConsoleBooterLockState
)
5238 locked
= gIOConsoleBooterLockState
;
5240 #endif /* HIBERNATION */
5241 else if (gIOConsoleLockTime
)
5243 clock_get_calendar_microtime(&now
, µsecs
);
5244 if (gIOConsoleLockTime
> now
)
5246 AbsoluteTime deadline
;
5247 clock_interval_to_deadline(gIOConsoleLockTime
- now
, kSecondScale
, &deadline
);
5248 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
5252 locked
= kOSBooleanTrue
;
5256 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
5259 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
5262 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
5264 OSIncrementAtomic( &gIOConsoleUsersSeed
);
5270 if (locked
== kOSBooleanTrue
) gIOScreenLockState
= kIOScreenLockLocked
;
5271 else if (gIOConsoleLockTime
) gIOScreenLockState
= kIOScreenLockUnlocked
;
5272 else gIOScreenLockState
= kIOScreenLockNoLock
;
5273 gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &gIOScreenLockState
, sizeof(gIOScreenLockState
));
5275 IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
5276 gIOScreenLockState
, gIOHibernateState
, (gIOConsoleBooterLockState
!= 0), now
, systemMessage
);
5278 #endif /* HIBERNATION */
5280 IOLockUnlock(gIOConsoleUsersLock
);
5284 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
5286 MessageClientsContext context
;
5288 context
.service
= getServiceRoot();
5289 context
.type
= kIOMessageConsoleSecurityChange
;
5290 context
.argument
= (void *) regEntry
;
5291 context
.argSize
= 0;
5293 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
5294 &messageClientsApplier
, &context
);
5298 IOReturn
IOResources::setProperties( OSObject
* properties
)
5301 const OSSymbol
* key
;
5302 OSDictionary
* dict
;
5303 OSCollectionIterator
* iter
;
5305 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
5306 if ( kIOReturnSuccess
!= err
)
5309 dict
= OSDynamicCast(OSDictionary
, properties
);
5311 return( kIOReturnBadArgument
);
5313 iter
= OSCollectionIterator::withCollection( dict
);
5315 return( kIOReturnBadArgument
);
5317 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
5319 if (gIOConsoleUsersKey
== key
) do
5321 OSArray
* consoleUsers
;
5322 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
5325 IOService::updateConsoleUsers(consoleUsers
, 0);
5329 publishResource( key
, dict
->getObject(key
) );
5334 return( kIOReturnSuccess
);
5338 * Helpers for matching dictionaries.
5339 * Keys existing in matching are checked in properties.
5340 * Keys may be a string or OSCollection of IOStrings
5343 bool IOService::compareProperty( OSDictionary
* matching
,
5350 value
= matching
->getObject( key
);
5353 prop
= copyProperty(key
);
5354 ok
= value
->isEqualTo(prop
);
5355 if (prop
) prop
->release();
5364 bool IOService::compareProperty( OSDictionary
* matching
,
5365 const OSString
* key
)
5371 value
= matching
->getObject( key
);
5374 prop
= copyProperty(key
);
5375 ok
= value
->isEqualTo(prop
);
5376 if (prop
) prop
->release();
5384 bool IOService::compareProperties( OSDictionary
* matching
,
5385 OSCollection
* keys
)
5387 OSCollectionIterator
* iter
;
5388 const OSString
* key
;
5391 if( !matching
|| !keys
)
5394 iter
= OSCollectionIterator::withCollection( keys
);
5397 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
5398 ok
= compareProperty( matching
, key
);
5402 keys
->release(); // !! consume a ref !!
5407 /* Helper to add a location matching dict to the table */
5409 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
5411 OSDictionary
* dict
;
5416 dict
= OSDictionary::withCapacity( 1 );
5418 table
->setObject( gIOLocationMatchKey
, dict
);
5426 * Go looking for a provider to match a location dict.
5429 IOService
* IOService::matchLocation( IOService
* /* client */ )
5433 parent
= getProvider();
5436 parent
= parent
->matchLocation( this );
5441 bool IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
5446 IORegistryEntry
* entry
;
5449 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
5455 count
= table
->getCount();
5458 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
5461 match
= ((kIOServiceClassDone
& options
) || (0 != metaCast(str
)));
5463 match
= (0 != metaCast( str
));
5464 if ((kIOServiceClassDone
& options
) && !match
) panic("classDone");
5466 if ((!match
) || (done
== count
)) break;
5469 obj
= table
->getObject( gIONameMatchKey
);
5472 match
= compareNames( obj
, changesOK
? &matched
: 0 );
5474 if( changesOK
&& matched
) {
5475 // leave a hint as to which name matched
5476 table
->setObject( gIONameMatchedKey
, matched
);
5479 if (done
== count
) break;
5482 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
5485 const OSSymbol
* sym
;
5488 sym
= copyLocation();
5490 match
= sym
->isEqualTo( str
);
5493 if ((!match
) || (done
== count
)) break;
5496 obj
= table
->getObject( gIOPropertyMatchKey
);
5499 OSDictionary
* dict
;
5500 OSDictionary
* nextDict
;
5504 dict
= dictionaryWithProperties();
5506 nextDict
= OSDynamicCast( OSDictionary
, obj
);
5510 iter
= OSCollectionIterator::withCollection(
5511 OSDynamicCast(OSCollection
, obj
));
5514 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
5515 iter
->getNextObject()))))) {
5516 match
= dict
->isEqualTo( nextDict
, nextDict
);
5525 if ((!match
) || (done
== count
)) break;
5528 obj
= table
->getObject( gIOPropertyExistsMatchKey
);
5531 OSDictionary
* dict
;
5536 dict
= dictionaryWithProperties();
5538 nextKey
= OSDynamicCast( OSString
, obj
);
5542 iter
= OSCollectionIterator::withCollection(
5543 OSDynamicCast(OSCollection
, obj
));
5546 || (iter
&& (0 != (nextKey
= OSDynamicCast(OSString
,
5547 iter
->getNextObject()))))) {
5548 match
= (0 != dict
->getObject(nextKey
));
5557 if ((!match
) || (done
== count
)) break;
5560 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
5563 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
5564 match
= (this == entry
);
5567 if ((!match
) || (done
== count
)) break;
5570 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
5573 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
5574 if ((!match
) || (done
== count
)) break;
5577 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
5581 IOService
* service
= 0;
5582 UInt32 serviceCount
= 0;
5585 iter
= getClientIterator();
5587 while( (service
= (IOService
*) iter
->getNextObject())) {
5588 if( kIOServiceInactiveState
& service
->__state
[0])
5590 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
5596 match
= (serviceCount
== num
->unsigned32BitValue());
5597 if ((!match
) || (done
== count
)) break;
5600 #define propMatch(key) \
5601 obj = table->getObject(key); \
5606 prop = copyProperty(key); \
5607 match = obj->isEqualTo(prop); \
5608 if (prop) prop->release(); \
5609 if ((!match) || (done == count)) break; \
5611 propMatch(gIOBSDNameKey
)
5612 propMatch(gIOBSDMajorKey
)
5613 propMatch(gIOBSDMinorKey
)
5614 propMatch(gIOBSDUnitKey
)
5619 if (did
) *did
= done
;
5623 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
5625 return (matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0));
5628 bool IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
5631 OSDictionary
* nextTable
;
5635 bool matchParent
= false;
5641 #if !CONFIG_EMBEDDED
5642 OSArray
* aliasServiceRegIds
= NULL
;
5643 IOService
* foundAlternateService
= NULL
;
5647 OSDictionary
* root
= table
;
5655 count
= table
->getCount();
5656 if (!(kIOServiceInternalDone
& options
))
5658 match
= where
->matchInternal(table
, options
, &done
);
5659 // don't call family if we've done all the entries in the table
5660 if ((!match
) || (done
== count
)) break;
5663 // pass in score from property table
5664 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
5666 // do family specific matching
5667 match
= where
->matchPropertyTable( table
, &score
);
5671 if( kIOLogMatch
& getDebugFlags( table
))
5672 LOG("%s: family specific matching fails\n", where
->getName());
5677 if (kIOServiceChangesOK
& options
) {
5679 newPri
= OSNumber::withNumber( score
, 32 );
5681 table
->setObject( gIOProbeScoreKey
, newPri
);
5687 matchParent
= false;
5689 nextTable
= OSDynamicCast(OSDictionary
,
5690 table
->getObject( gIOParentMatchKey
));
5692 // look for a matching entry anywhere up to root
5699 table
= OSDynamicCast(OSDictionary
,
5700 table
->getObject( gIOLocationMatchKey
));
5702 // look for a matching entry at matchLocation()
5704 where
= where
->getProvider();
5705 if (where
&& (where
= where
->matchLocation(where
))) continue;
5715 if(matchParent
== true) {
5716 #if !CONFIG_EMBEDDED
5717 // check if service has an alias to search its other "parents" if a parent match isn't found
5718 OSObject
* prop
= where
->copyProperty(gIOServiceLegacyMatchingRegistryIDKey
);
5719 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, prop
);
5720 if(alternateRegistryID
!= NULL
) {
5721 if(aliasServiceRegIds
== NULL
)
5723 aliasServiceRegIds
= OSArray::withCapacity(sizeof(alternateRegistryID
));
5725 aliasServiceRegIds
->setObject(alternateRegistryID
);
5727 OSSafeReleaseNULL(prop
);
5734 where
= where
->getProvider();
5735 #if !CONFIG_EMBEDDED
5737 // there were no matching parent services, check to see if there are aliased services that have a matching parent
5738 if(aliasServiceRegIds
!= NULL
) {
5739 unsigned int numAliasedServices
= aliasServiceRegIds
->getCount();
5740 if(numAliasedServices
!= 0) {
5741 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, aliasServiceRegIds
->getObject(numAliasedServices
- 1));
5742 if(alternateRegistryID
!= NULL
) {
5743 OSDictionary
* alternateMatchingDict
= IOService::registryEntryIDMatching(alternateRegistryID
->unsigned64BitValue());
5744 aliasServiceRegIds
->removeObject(numAliasedServices
- 1);
5745 if(alternateMatchingDict
!= NULL
) {
5746 OSSafeReleaseNULL(foundAlternateService
);
5747 foundAlternateService
= IOService::copyMatchingService(alternateMatchingDict
);
5748 alternateMatchingDict
->release();
5749 if(foundAlternateService
!= NULL
) {
5750 where
= foundAlternateService
;
5759 while( where
!= NULL
);
5761 #if !CONFIG_EMBEDDED
5762 OSSafeReleaseNULL(foundAlternateService
);
5763 OSSafeReleaseNULL(aliasServiceRegIds
);
5769 OSSerialize
* s
= OSSerialize::withCapacity(128);
5771 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
5780 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
5781 UInt32 type
, OSDictionary
* properties
,
5782 IOUserClient
** handler
)
5784 const OSSymbol
*userClientClass
= 0;
5785 IOUserClient
*client
;
5789 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
5790 return kIOReturnSuccess
;
5792 // First try my own properties for a user client class name
5793 prop
= copyProperty(gIOUserClientClassKey
);
5795 if (OSDynamicCast(OSSymbol
, prop
))
5796 userClientClass
= (const OSSymbol
*) prop
;
5797 else if (OSDynamicCast(OSString
, prop
)) {
5798 userClientClass
= OSSymbol::withString((OSString
*) prop
);
5799 if (userClientClass
)
5800 setProperty(gIOUserClientClassKey
,
5801 (OSObject
*) userClientClass
);
5805 // Didn't find one so lets just bomb out now without further ado.
5806 if (!userClientClass
)
5808 OSSafeReleaseNULL(prop
);
5809 return kIOReturnUnsupported
;
5812 // This reference is consumed by the IOServiceOpen call
5813 temp
= OSMetaClass::allocClassWithName(userClientClass
);
5814 OSSafeReleaseNULL(prop
);
5816 return kIOReturnNoMemory
;
5818 if (OSDynamicCast(IOUserClient
, temp
))
5819 client
= (IOUserClient
*) temp
;
5822 return kIOReturnUnsupported
;
5825 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
5827 return kIOReturnBadArgument
;
5830 if ( !client
->attach(this) ) {
5832 return kIOReturnUnsupported
;
5835 if ( !client
->start(this) ) {
5836 client
->detach(this);
5838 return kIOReturnUnsupported
;
5842 return kIOReturnSuccess
;
5845 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
5846 UInt32 type
, IOUserClient
** handler
)
5848 return( kIOReturnUnsupported
);
5851 IOReturn
IOService::requestProbe( IOOptionBits options
)
5853 return( kIOReturnUnsupported
);
5857 * Convert an IOReturn to text. Subclasses which add additional
5858 * IOReturn's should override this method and call
5859 * super::stringFromReturn if the desired value is not found.
5862 const char * IOService::stringFromReturn( IOReturn rtn
)
5864 static const IONamedValue IOReturn_values
[] = {
5865 {kIOReturnSuccess
, "success" },
5866 {kIOReturnError
, "general error" },
5867 {kIOReturnNoMemory
, "memory allocation error" },
5868 {kIOReturnNoResources
, "resource shortage" },
5869 {kIOReturnIPCError
, "Mach IPC failure" },
5870 {kIOReturnNoDevice
, "no such device" },
5871 {kIOReturnNotPrivileged
, "privilege violation" },
5872 {kIOReturnBadArgument
, "invalid argument" },
5873 {kIOReturnLockedRead
, "device is read locked" },
5874 {kIOReturnLockedWrite
, "device is write locked" },
5875 {kIOReturnExclusiveAccess
, "device is exclusive access" },
5876 {kIOReturnBadMessageID
, "bad IPC message ID" },
5877 {kIOReturnUnsupported
, "unsupported function" },
5878 {kIOReturnVMError
, "virtual memory error" },
5879 {kIOReturnInternalError
, "internal driver error" },
5880 {kIOReturnIOError
, "I/O error" },
5881 {kIOReturnCannotLock
, "cannot acquire lock" },
5882 {kIOReturnNotOpen
, "device is not open" },
5883 {kIOReturnNotReadable
, "device is not readable" },
5884 {kIOReturnNotWritable
, "device is not writeable" },
5885 {kIOReturnNotAligned
, "alignment error" },
5886 {kIOReturnBadMedia
, "media error" },
5887 {kIOReturnStillOpen
, "device is still open" },
5888 {kIOReturnRLDError
, "rld failure" },
5889 {kIOReturnDMAError
, "DMA failure" },
5890 {kIOReturnBusy
, "device is busy" },
5891 {kIOReturnTimeout
, "I/O timeout" },
5892 {kIOReturnOffline
, "device is offline" },
5893 {kIOReturnNotReady
, "device is not ready" },
5894 {kIOReturnNotAttached
, "device/channel is not attached" },
5895 {kIOReturnNoChannels
, "no DMA channels available" },
5896 {kIOReturnNoSpace
, "no space for data" },
5897 {kIOReturnPortExists
, "device port already exists" },
5898 {kIOReturnCannotWire
, "cannot wire physical memory" },
5899 {kIOReturnNoInterrupt
, "no interrupt attached" },
5900 {kIOReturnNoFrames
, "no DMA frames enqueued" },
5901 {kIOReturnMessageTooLarge
, "message is too large" },
5902 {kIOReturnNotPermitted
, "operation is not permitted" },
5903 {kIOReturnNoPower
, "device is without power" },
5904 {kIOReturnNoMedia
, "media is not present" },
5905 {kIOReturnUnformattedMedia
, "media is not formatted" },
5906 {kIOReturnUnsupportedMode
, "unsupported mode" },
5907 {kIOReturnUnderrun
, "data underrun" },
5908 {kIOReturnOverrun
, "data overrun" },
5909 {kIOReturnDeviceError
, "device error" },
5910 {kIOReturnNoCompletion
, "no completion routine" },
5911 {kIOReturnAborted
, "operation was aborted" },
5912 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
5913 {kIOReturnNotResponding
, "device is not responding" },
5914 {kIOReturnInvalid
, "unanticipated driver error" },
5918 return IOFindNameForValue(rtn
, IOReturn_values
);
5922 * Convert an IOReturn to an errno.
5924 int IOService::errnoFromReturn( IOReturn rtn
)
5926 if (unix_err(err_get_code(rtn
)) == rtn
)
5927 return err_get_code(rtn
);
5931 case kIOReturnSuccess
:
5933 case kIOReturnNoMemory
:
5935 case kIOReturnNoDevice
:
5937 case kIOReturnVMError
:
5939 case kIOReturnNotPermitted
:
5941 case kIOReturnNotPrivileged
:
5943 case kIOReturnIOError
:
5945 case kIOReturnNotWritable
:
5947 case kIOReturnBadArgument
:
5949 case kIOReturnUnsupported
:
5953 case kIOReturnNoPower
:
5955 case kIOReturnDeviceError
:
5957 case kIOReturnTimeout
:
5959 case kIOReturnMessageTooLarge
:
5961 case kIOReturnNoSpace
:
5963 case kIOReturnCannotLock
:
5967 case kIOReturnBadMessageID
:
5968 case kIOReturnNoCompletion
:
5969 case kIOReturnNotAligned
:
5971 case kIOReturnNotReady
:
5973 case kIOReturnRLDError
:
5975 case kIOReturnPortExists
:
5976 case kIOReturnStillOpen
:
5978 case kIOReturnExclusiveAccess
:
5979 case kIOReturnLockedRead
:
5980 case kIOReturnLockedWrite
:
5981 case kIOReturnNotOpen
:
5982 case kIOReturnNotReadable
:
5984 case kIOReturnCannotWire
:
5985 case kIOReturnNoResources
:
5987 case kIOReturnAborted
:
5988 case kIOReturnOffline
:
5989 case kIOReturnNotResponding
:
5991 case kIOReturnBadMedia
:
5992 case kIOReturnNoMedia
:
5993 case kIOReturnNotAttached
:
5994 case kIOReturnUnformattedMedia
:
5995 return(ENXIO
); // (media error)
5996 case kIOReturnDMAError
:
5997 case kIOReturnOverrun
:
5998 case kIOReturnUnderrun
:
5999 return(EIO
); // (transfer error)
6000 case kIOReturnNoBandwidth
:
6001 case kIOReturnNoChannels
:
6002 case kIOReturnNoFrames
:
6003 case kIOReturnNoInterrupt
:
6004 return(EIO
); // (hardware error)
6005 case kIOReturnError
:
6006 case kIOReturnInternalError
:
6007 case kIOReturnInvalid
:
6008 return(EIO
); // (generic error)
6009 case kIOReturnIPCError
:
6010 return(EIO
); // (ipc error)
6012 return(EIO
); // (all other errors)
6016 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
6020 * Generic entry point for calls from the provider. A return value of
6021 * kIOReturnSuccess indicates that the message was received, and where
6022 * applicable, that it was successful.
6025 return kIOReturnUnsupported
;
6032 IOItemCount
IOService::getDeviceMemoryCount( void )
6037 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
6039 count
= array
->getCount();
6046 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
6049 IODeviceMemory
* range
;
6051 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
6053 range
= (IODeviceMemory
*) array
->getObject( index
);
6060 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
6061 IOOptionBits options
)
6063 IODeviceMemory
* range
;
6066 range
= getDeviceMemoryWithIndex( index
);
6068 map
= range
->map( options
);
6075 OSArray
* IOService::getDeviceMemory( void )
6077 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
6081 void IOService::setDeviceMemory( OSArray
* array
)
6083 setProperty( gIODeviceMemoryKey
, array
);
6087 * For machines where the transfers on an I/O bus can stall because
6088 * the CPU is in an idle mode, These APIs allow a driver to specify
6089 * the maximum bus stall that they can handle. 0 indicates no limit.
6092 setCPUSnoopDelay(UInt32 __unused ns
)
6094 #if defined(__i386__) || defined(__x86_64__)
6095 ml_set_maxsnoop(ns
);
6096 #endif /* defined(__i386__) || defined(__x86_64__) */
6102 #if defined(__i386__) || defined(__x86_64__)
6103 return ml_get_maxsnoop();
6106 #endif /* defined(__i386__) || defined(__x86_64__) */
6109 #if defined(__i386__) || defined(__x86_64__)
6111 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
6113 static const UInt kNoReplace
= -1U; // Must be an illegal index
6114 UInt replace
= kNoReplace
;
6115 bool setCpuDelay
= false;
6117 IORecursiveLockLock(sCpuDelayLock
);
6119 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
6120 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
6121 IOService
* holder
= NULL
;
6124 const CpuDelayEntry ne
= {service
, ns
, delayType
};
6126 // Set maximum delay.
6127 for (UInt i
= 0; i
< count
; i
++) {
6128 IOService
*thisService
= entries
[i
].fService
;
6129 bool sameType
= (delayType
== entries
[i
].fDelayType
);
6130 if ((service
== thisService
) && sameType
)
6132 else if (!thisService
) {
6133 if (kNoReplace
== replace
)
6136 else if (sameType
) {
6137 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
6141 holder
= thisService
;
6147 if (kNoReplace
== replace
)
6148 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
6150 entries
[replace
] = ne
;
6153 ns
= -1U; // Set to max unsigned, i.e. no restriction
6155 for (UInt i
= 0; i
< count
; i
++) {
6156 // Clear a maximum delay.
6157 IOService
*thisService
= entries
[i
].fService
;
6158 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
6159 UInt32 thisMax
= entries
[i
].fMaxDelay
;
6160 if (service
== thisService
)
6162 else if (thisMax
< ns
) {
6164 holder
= thisService
;
6169 // Check if entry found
6170 if (kNoReplace
!= replace
) {
6171 entries
[replace
].fService
= 0; // Null the entry
6178 if (holder
&& debug_boot_arg
) {
6179 strlcpy(sCPULatencyHolderName
[delayType
], holder
->getName(), sizeof(sCPULatencyHolderName
[delayType
]));
6182 // Must be safe to call from locked context
6183 if (delayType
== kCpuDelayBusStall
)
6185 ml_set_maxbusdelay(ns
);
6187 else if (delayType
== kCpuDelayInterrupt
)
6189 ml_set_maxintdelay(ns
);
6191 sCPULatencyHolder
[delayType
]->setValue(holder
? holder
->getRegistryEntryID() : 0);
6192 sCPULatencySet
[delayType
]->setValue(ns
);
6194 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
6196 if (handlers
) for (unsigned int idx
= 0;
6197 (target
= (IOService
*) handlers
->getObject(idx
));
6200 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
6201 (void *) (uintptr_t) ns
, holder
,
6206 IORecursiveLockUnlock(sCpuDelayLock
);
6210 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
6212 IOReturn result
= kIOReturnNotFound
;
6216 IORecursiveLockLock(sCpuDelayLock
);
6220 if (enable
&& !sCpuLatencyHandlers
[delayType
])
6221 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
6222 array
= sCpuLatencyHandlers
[delayType
];
6225 idx
= array
->getNextIndexOfObject(target
, 0);
6230 array
->removeObject(idx
);
6231 result
= kIOReturnSuccess
;
6237 result
= kIOReturnExclusiveAccess
;
6240 array
->setObject(target
);
6242 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
6243 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
6244 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
6245 IOService
* holder
= NULL
;
6247 for (UInt i
= 0; i
< count
; i
++) {
6248 if (entries
[i
].fService
6249 && (delayType
== entries
[i
].fDelayType
)
6250 && (entries
[i
].fMaxDelay
< ns
)) {
6251 ns
= entries
[i
].fMaxDelay
;
6252 holder
= entries
[i
].fService
;
6255 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
6256 (void *) (uintptr_t) ns
, holder
,
6258 result
= kIOReturnSuccess
;
6263 IORecursiveLockUnlock(sCpuDelayLock
);
6268 #endif /* defined(__i386__) || defined(__x86_64__) */
6271 requireMaxBusStall(UInt32 __unused ns
)
6273 #if defined(__i386__) || defined(__x86_64__)
6274 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
6279 requireMaxInterruptDelay(uint32_t __unused ns
)
6281 #if defined(__i386__) || defined(__x86_64__)
6282 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
6290 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
6292 IOInterruptController
*interruptController
;
6295 OSSymbol
*interruptControllerName
;
6297 IOInterruptSource
*interruptSources
;
6299 // Get the parents list from the nub.
6300 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
6301 if (array
== 0) return kIOReturnNoResources
;
6303 // Allocate space for the IOInterruptSources if needed... then return early.
6304 if (nub
->_interruptSources
== 0) {
6305 numSources
= array
->getCount();
6306 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
6307 if (interruptSources
== 0) return kIOReturnNoMemory
;
6309 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
6311 nub
->_numInterruptSources
= numSources
;
6312 nub
->_interruptSources
= interruptSources
;
6313 return kIOReturnSuccess
;
6316 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
6317 if (interruptControllerName
== 0) return kIOReturnNoResources
;
6319 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
6320 if (interruptController
== 0) return kIOReturnNoResources
;
6322 // Get the interrupt numbers from the nub.
6323 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
6324 if (array
== 0) return kIOReturnNoResources
;
6325 data
= OSDynamicCast(OSData
, array
->getObject(source
));
6326 if (data
== 0) return kIOReturnNoResources
;
6328 // Set the interruptController and interruptSource in the nub's table.
6329 interruptSources
= nub
->_interruptSources
;
6330 interruptSources
[source
].interruptController
= interruptController
;
6331 interruptSources
[source
].vectorData
= data
;
6333 return kIOReturnSuccess
;
6336 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
6340 /* Make sure the _interruptSources are set */
6341 if (_interruptSources
== 0) {
6342 ret
= resolveInterrupt(this, source
);
6343 if (ret
!= kIOReturnSuccess
) return ret
;
6346 /* Make sure the local source number is valid */
6347 if ((source
< 0) || (source
>= _numInterruptSources
))
6348 return kIOReturnNoInterrupt
;
6350 /* Look up the contoller for the local source */
6351 *interruptController
= _interruptSources
[source
].interruptController
;
6353 if (*interruptController
== NULL
) {
6354 if (!resolve
) return kIOReturnNoInterrupt
;
6356 /* Try to reslove the interrupt */
6357 ret
= resolveInterrupt(this, source
);
6358 if (ret
!= kIOReturnSuccess
) return ret
;
6360 *interruptController
= _interruptSources
[source
].interruptController
;
6363 return kIOReturnSuccess
;
6366 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
6367 IOInterruptAction handler
,
6370 IOInterruptController
*interruptController
;
6373 ret
= lookupInterrupt(source
, true, &interruptController
);
6374 if (ret
!= kIOReturnSuccess
) return ret
;
6376 /* Register the source */
6377 return interruptController
->registerInterrupt(this, source
, target
,
6378 (IOInterruptHandler
)handler
,
6382 IOReturn
IOService::unregisterInterrupt(int source
)
6384 IOInterruptController
*interruptController
;
6387 ret
= lookupInterrupt(source
, false, &interruptController
);
6388 if (ret
!= kIOReturnSuccess
) return ret
;
6390 /* Unregister the source */
6391 return interruptController
->unregisterInterrupt(this, source
);
6394 IOReturn
IOService::addInterruptStatistics(IOInterruptAccountingData
* statistics
, int source
)
6396 IOReportLegend
* legend
= NULL
;
6397 IOInterruptAccountingData
* oldValue
= NULL
;
6398 IOInterruptAccountingReporter
* newArray
= NULL
;
6399 char subgroupName
[64];
6400 int newArraySize
= 0;
6404 return kIOReturnBadArgument
;
6408 * We support statistics on a maximum of 256 interrupts per nub; if a nub
6409 * has more than 256 interrupt specifiers associated with it, and tries
6410 * to register a high interrupt index with interrupt accounting, panic.
6411 * Having more than 256 interrupts associated with a single nub is
6412 * probably a sign that something fishy is going on.
6414 if (source
> IA_INDEX_MAX
) {
6415 panic("addInterruptStatistics called for an excessively large index (%d)", source
);
6419 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
6420 * leaving it as is because the likelihood of contention where we are
6421 * actually growing the array is minimal (we would realistically need
6422 * to be starting a driver for the first time, with an IOReporting
6423 * client already in place). Nonetheless, cleanup that can be done
6424 * to adhere to best practices; it'll make the code more complicated,
6427 IOLockLock(reserved
->interruptStatisticsLock
);
6430 * Lazily allocate the statistics array.
6432 if (!reserved
->interruptStatisticsArray
) {
6433 reserved
->interruptStatisticsArray
= IONew(IOInterruptAccountingReporter
, 1);
6434 assert(reserved
->interruptStatisticsArray
);
6435 reserved
->interruptStatisticsArrayCount
= 1;
6436 bzero(reserved
->interruptStatisticsArray
, sizeof(*reserved
->interruptStatisticsArray
));
6439 if (source
>= reserved
->interruptStatisticsArrayCount
) {
6441 * We're still within the range of supported indices, but we are out
6442 * of space in the current array. Do a nasty realloc (because
6443 * IORealloc isn't a thing) here. We'll double the size with each
6446 * Yes, the "next power of 2" could be more efficient; but this will
6447 * be invoked incredibly rarely. Who cares.
6449 newArraySize
= (reserved
->interruptStatisticsArrayCount
<< 1);
6451 while (newArraySize
<= source
)
6452 newArraySize
= (newArraySize
<< 1);
6453 newArray
= IONew(IOInterruptAccountingReporter
, newArraySize
);
6458 * TODO: This even zeroes the memory it is about to overwrite.
6459 * Shameful; fix it. Not particularly high impact, however.
6461 bzero(newArray
, newArraySize
* sizeof(*newArray
));
6462 memcpy(newArray
, reserved
->interruptStatisticsArray
, reserved
->interruptStatisticsArrayCount
* sizeof(*newArray
));
6463 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
6464 reserved
->interruptStatisticsArray
= newArray
;
6465 reserved
->interruptStatisticsArrayCount
= newArraySize
;
6468 if (!reserved
->interruptStatisticsArray
[source
].reporter
) {
6470 * We don't have a reporter associated with this index yet, so we
6471 * need to create one.
6474 * TODO: Some statistics do in fact have common units (time); should this be
6475 * split into separate reporters to communicate this?
6477 reserved
->interruptStatisticsArray
[source
].reporter
= IOSimpleReporter::with(this, kIOReportCategoryPower
, kIOReportUnitNone
);
6480 * Each statistic is given an identifier based on the interrupt index (which
6481 * should be unique relative to any single nub) and the statistic involved.
6482 * We should now have a sane (small and positive) index, so start
6483 * constructing the channels for statistics.
6485 for (i
= 0; i
< IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS
; i
++) {
6487 * TODO: Currently, this does not add channels for disabled statistics.
6488 * Will this be confusing for clients? If so, we should just add the
6489 * channels; we can avoid updating the channels even if they exist.
6491 if (IA_GET_STATISTIC_ENABLED(i
))
6492 reserved
->interruptStatisticsArray
[source
].reporter
->addChannel(IA_GET_CHANNEL_ID(source
, i
), kInterruptAccountingStatisticNameArray
[i
]);
6496 * We now need to add the legend for this reporter to the registry.
6498 OSObject
* prop
= copyProperty(kIOReportLegendKey
);
6499 legend
= IOReportLegend::with(OSDynamicCast(OSArray
, prop
));
6500 OSSafeReleaseNULL(prop
);
6503 * Note that while we compose the subgroup name, we do not need to
6504 * manage its lifecycle (the reporter will handle this).
6506 snprintf(subgroupName
, sizeof(subgroupName
), "%s %d", getName(), source
);
6507 subgroupName
[sizeof(subgroupName
) - 1] = 0;
6508 legend
->addReporterLegend(reserved
->interruptStatisticsArray
[source
].reporter
, kInterruptAccountingGroupName
, subgroupName
);
6509 setProperty(kIOReportLegendKey
, legend
->getLegend());
6513 * TODO: Is this a good idea? Probably not; my assumption is it opts
6514 * all entities who register interrupts into public disclosure of all
6515 * IOReporting channels. Unfortunately, this appears to be as fine
6518 setProperty(kIOReportLegendPublicKey
, true);
6522 * Don't stomp existing entries. If we are about to, panic; this
6523 * probably means we failed to tear down our old interrupt source
6526 oldValue
= reserved
->interruptStatisticsArray
[source
].statistics
;
6529 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source
);
6532 reserved
->interruptStatisticsArray
[source
].statistics
= statistics
;
6535 * Inherit the reporter values for each statistic. The target may
6536 * be torn down as part of the runtime of the service (especially
6537 * for sleep/wake), so we inherit in order to avoid having values
6538 * reset for no apparent reason. Our statistics are ultimately
6539 * tied to the index and the sevice, not to an individual target,
6540 * so we should maintain them accordingly.
6542 interruptAccountingDataInheritChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
6544 IOLockUnlock(reserved
->interruptStatisticsLock
);
6546 return kIOReturnSuccess
;
6549 IOReturn
IOService::removeInterruptStatistics(int source
)
6551 IOInterruptAccountingData
* value
= NULL
;
6554 return kIOReturnBadArgument
;
6557 IOLockLock(reserved
->interruptStatisticsLock
);
6560 * We dynamically grow the statistics array, so an excessively
6561 * large index value has NEVER been registered. This either
6562 * means our cap on the array size is too small (unlikely), or
6563 * that we have been passed a corrupt index (this must be passed
6564 * the plain index into the interrupt specifier list).
6566 if (source
>= reserved
->interruptStatisticsArrayCount
) {
6567 panic("removeInterruptStatistics called for index %d, which was never registered", source
);
6570 assert(reserved
->interruptStatisticsArray
);
6573 * If there is no existing entry, we are most likely trying to
6574 * free an interrupt owner twice, or we have corrupted the
6577 value
= reserved
->interruptStatisticsArray
[source
].statistics
;
6580 panic("removeInterruptStatistics called for empty index %d", source
);
6584 * We update the statistics, so that any delta with the reporter
6585 * state is not lost.
6587 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
6588 reserved
->interruptStatisticsArray
[source
].statistics
= NULL
;
6589 IOLockUnlock(reserved
->interruptStatisticsLock
);
6591 return kIOReturnSuccess
;
6594 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
6596 IOInterruptController
*interruptController
;
6599 ret
= lookupInterrupt(source
, true, &interruptController
);
6600 if (ret
!= kIOReturnSuccess
) return ret
;
6602 /* Return the type */
6603 return interruptController
->getInterruptType(this, source
, interruptType
);
6606 IOReturn
IOService::enableInterrupt(int source
)
6608 IOInterruptController
*interruptController
;
6611 ret
= lookupInterrupt(source
, false, &interruptController
);
6612 if (ret
!= kIOReturnSuccess
) return ret
;
6614 /* Enable the source */
6615 return interruptController
->enableInterrupt(this, source
);
6618 IOReturn
IOService::disableInterrupt(int source
)
6620 IOInterruptController
*interruptController
;
6623 ret
= lookupInterrupt(source
, false, &interruptController
);
6624 if (ret
!= kIOReturnSuccess
) return ret
;
6626 /* Disable the source */
6627 return interruptController
->disableInterrupt(this, source
);
6630 IOReturn
IOService::causeInterrupt(int source
)
6632 IOInterruptController
*interruptController
;
6635 ret
= lookupInterrupt(source
, false, &interruptController
);
6636 if (ret
!= kIOReturnSuccess
) return ret
;
6638 /* Cause an interrupt for the source */
6639 return interruptController
->causeInterrupt(this, source
);
6642 IOReturn
IOService::configureReport(IOReportChannelList
*channelList
,
6643 IOReportConfigureAction action
,
6649 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
6650 if ( channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
6651 if (pwrMgt
) configurePowerStatesReport(action
, result
);
6652 else return kIOReturnUnsupported
;
6654 else if ( channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
6655 if (pwrMgt
) configureSimplePowerReport(action
, result
);
6656 else return kIOReturnUnsupported
;
6660 IOLockLock(reserved
->interruptStatisticsLock
);
6662 /* The array count is signed (because the interrupt indices are signed), hence the cast */
6663 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
6664 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
6666 * If the reporter is currently associated with the statistics
6667 * for an event source, we may need to update the reporter.
6669 if (reserved
->interruptStatisticsArray
[cnt
].statistics
)
6670 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
6672 reserved
->interruptStatisticsArray
[cnt
].reporter
->configureReport(channelList
, action
, result
, destination
);
6676 IOLockUnlock(reserved
->interruptStatisticsLock
);
6678 return kIOReturnSuccess
;
6681 IOReturn
IOService::updateReport(IOReportChannelList
*channelList
,
6682 IOReportUpdateAction action
,
6688 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
6689 if ( channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
6690 if (pwrMgt
) updatePowerStatesReport(action
, result
, destination
);
6691 else return kIOReturnUnsupported
;
6693 else if ( channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
6694 if (pwrMgt
) updateSimplePowerReport(action
, result
, destination
);
6695 else return kIOReturnUnsupported
;
6699 IOLockLock(reserved
->interruptStatisticsLock
);
6701 /* The array count is signed (because the interrupt indices are signed), hence the cast */
6702 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
6703 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
6705 * If the reporter is currently associated with the statistics
6706 * for an event source, we need to update the reporter.
6708 if (reserved
->interruptStatisticsArray
[cnt
].statistics
)
6709 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
6711 reserved
->interruptStatisticsArray
[cnt
].reporter
->updateReport(channelList
, action
, result
, destination
);
6715 IOLockUnlock(reserved
->interruptStatisticsLock
);
6717 return kIOReturnSuccess
;
6720 uint64_t IOService::getAuthorizationID( void )
6722 return reserved
->authorizationID
;
6725 IOReturn
IOService::setAuthorizationID( uint64_t authorizationID
)
6727 OSObject
* entitlement
;
6730 entitlement
= IOUserClient::copyClientEntitlement( current_task( ), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
6734 if ( entitlement
== kOSBooleanTrue
)
6736 reserved
->authorizationID
= authorizationID
;
6738 status
= kIOReturnSuccess
;
6742 status
= kIOReturnNotPrivileged
;
6745 entitlement
->release( );
6749 status
= kIOReturnNotPrivileged
;
6756 OSMetaClassDefineReservedUsed(IOService
, 0);
6757 OSMetaClassDefineReservedUsed(IOService
, 1);
6758 OSMetaClassDefineReservedUnused(IOService
, 2);
6759 OSMetaClassDefineReservedUnused(IOService
, 3);
6760 OSMetaClassDefineReservedUnused(IOService
, 4);
6761 OSMetaClassDefineReservedUnused(IOService
, 5);
6762 OSMetaClassDefineReservedUnused(IOService
, 6);
6763 OSMetaClassDefineReservedUnused(IOService
, 7);
6765 OSMetaClassDefineReservedUsed(IOService
, 0);
6766 OSMetaClassDefineReservedUsed(IOService
, 1);
6767 OSMetaClassDefineReservedUsed(IOService
, 2);
6768 OSMetaClassDefineReservedUsed(IOService
, 3);
6769 OSMetaClassDefineReservedUsed(IOService
, 4);
6770 OSMetaClassDefineReservedUsed(IOService
, 5);
6771 OSMetaClassDefineReservedUsed(IOService
, 6);
6772 OSMetaClassDefineReservedUsed(IOService
, 7);
6774 OSMetaClassDefineReservedUnused(IOService
, 8);
6775 OSMetaClassDefineReservedUnused(IOService
, 9);
6776 OSMetaClassDefineReservedUnused(IOService
, 10);
6777 OSMetaClassDefineReservedUnused(IOService
, 11);
6778 OSMetaClassDefineReservedUnused(IOService
, 12);
6779 OSMetaClassDefineReservedUnused(IOService
, 13);
6780 OSMetaClassDefineReservedUnused(IOService
, 14);
6781 OSMetaClassDefineReservedUnused(IOService
, 15);
6782 OSMetaClassDefineReservedUnused(IOService
, 16);
6783 OSMetaClassDefineReservedUnused(IOService
, 17);
6784 OSMetaClassDefineReservedUnused(IOService
, 18);
6785 OSMetaClassDefineReservedUnused(IOService
, 19);
6786 OSMetaClassDefineReservedUnused(IOService
, 20);
6787 OSMetaClassDefineReservedUnused(IOService
, 21);
6788 OSMetaClassDefineReservedUnused(IOService
, 22);
6789 OSMetaClassDefineReservedUnused(IOService
, 23);
6790 OSMetaClassDefineReservedUnused(IOService
, 24);
6791 OSMetaClassDefineReservedUnused(IOService
, 25);
6792 OSMetaClassDefineReservedUnused(IOService
, 26);
6793 OSMetaClassDefineReservedUnused(IOService
, 27);
6794 OSMetaClassDefineReservedUnused(IOService
, 28);
6795 OSMetaClassDefineReservedUnused(IOService
, 29);
6796 OSMetaClassDefineReservedUnused(IOService
, 30);
6797 OSMetaClassDefineReservedUnused(IOService
, 31);
6798 OSMetaClassDefineReservedUnused(IOService
, 32);
6799 OSMetaClassDefineReservedUnused(IOService
, 33);
6800 OSMetaClassDefineReservedUnused(IOService
, 34);
6801 OSMetaClassDefineReservedUnused(IOService
, 35);
6802 OSMetaClassDefineReservedUnused(IOService
, 36);
6803 OSMetaClassDefineReservedUnused(IOService
, 37);
6804 OSMetaClassDefineReservedUnused(IOService
, 38);
6805 OSMetaClassDefineReservedUnused(IOService
, 39);
6806 OSMetaClassDefineReservedUnused(IOService
, 40);
6807 OSMetaClassDefineReservedUnused(IOService
, 41);
6808 OSMetaClassDefineReservedUnused(IOService
, 42);
6809 OSMetaClassDefineReservedUnused(IOService
, 43);
6810 OSMetaClassDefineReservedUnused(IOService
, 44);
6811 OSMetaClassDefineReservedUnused(IOService
, 45);
6812 OSMetaClassDefineReservedUnused(IOService
, 46);
6813 OSMetaClassDefineReservedUnused(IOService
, 47);