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>
30 #include <IOKit/IOService.h>
31 #include <libkern/OSDebug.h>
32 #include <libkern/c++/OSContainers.h>
33 #include <libkern/c++/OSKext.h>
34 #include <libkern/c++/OSUnserialize.h>
35 #include <libkern/c++/OSKext.h>
36 #include <libkern/Block.h>
37 #include <IOKit/IOCatalogue.h>
38 #include <IOKit/IOCommand.h>
39 #include <IOKit/IODeviceTreeSupport.h>
40 #include <IOKit/IODeviceMemory.h>
41 #include <IOKit/IOInterrupts.h>
42 #include <IOKit/IOInterruptController.h>
43 #include <IOKit/IOPlatformExpert.h>
44 #include <IOKit/IOMessage.h>
45 #include <IOKit/IOLib.h>
46 #include <IOKit/IOKitKeysPrivate.h>
47 #include <IOKit/IOBSD.h>
48 #include <IOKit/IOUserClient.h>
49 #include <IOKit/IOUserServer.h>
50 #include <IOKit/IOWorkLoop.h>
51 #include <IOKit/IOTimeStamp.h>
52 #include <IOKit/IOHibernatePrivate.h>
53 #include <IOKit/IOInterruptAccountingPrivate.h>
54 #include <IOKit/IOKernelReporters.h>
55 #include <IOKit/AppleKeyStoreInterface.h>
56 #include <IOKit/pwr_mgt/RootDomain.h>
57 #include <IOKit/IOCPU.h>
58 #include <mach/sync_policy.h>
59 #include <mach/thread_info.h>
60 #include <IOKit/assert.h>
61 #include <sys/errno.h>
62 #include <sys/kdebug.h>
65 #include <machine/pal_routines.h>
70 #define IOSERVICE_OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
72 // disabled since lockForArbitration() can be held externally
73 #define DEBUG_NOTIFIER_LOCKED 0
76 kIOUserServerCheckInTimeoutSecs
= 120ULL
79 #include "IOServicePrivate.h"
80 #include "IOKitKernelInternal.h"
82 // take lockForArbitration before LOCKNOTIFY
84 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
86 #define super IORegistryEntry
88 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
90 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
91 OSDefineMetaClassAndStructors(_IOServiceNullNotifier
, IONotifier
)
93 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
95 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
97 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
99 OSDefineMetaClassAndStructors(IOResources
, IOService
)
100 OSDefineMetaClassAndStructors(IOUserResources
, IOService
)
102 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
104 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
106 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
108 static IOPlatformExpert
* gIOPlatform
;
109 static class IOPMrootDomain
* gIOPMRootDomain
;
110 const IORegistryPlane
* gIOServicePlane
;
111 const IORegistryPlane
* gIOPowerPlane
;
112 const OSSymbol
* gIODeviceMemoryKey
;
113 const OSSymbol
* gIOInterruptControllersKey
;
114 const OSSymbol
* gIOInterruptSpecifiersKey
;
116 const OSSymbol
* gIOResourcesKey
;
117 const OSSymbol
* gIOUserResourcesKey
;
118 const OSSymbol
* gIOResourceMatchKey
;
119 const OSSymbol
* gIOResourceMatchedKey
;
120 const OSSymbol
* gIOResourceIOKitKey
;
122 const OSSymbol
* gIOProviderClassKey
;
123 const OSSymbol
* gIONameMatchKey
;
124 const OSSymbol
* gIONameMatchedKey
;
125 const OSSymbol
* gIOPropertyMatchKey
;
126 const OSSymbol
* gIOPropertyExistsMatchKey
;
127 const OSSymbol
* gIOLocationMatchKey
;
128 const OSSymbol
* gIOParentMatchKey
;
129 const OSSymbol
* gIOPathMatchKey
;
130 const OSSymbol
* gIOMatchCategoryKey
;
131 const OSSymbol
* gIODefaultMatchCategoryKey
;
132 const OSSymbol
* gIOMatchedServiceCountKey
;
133 const OSSymbol
* gIOMatchedPersonalityKey
;
134 const OSSymbol
* gIORematchPersonalityKey
;
135 const OSSymbol
* gIORematchCountKey
;
136 const OSSymbol
* gIODEXTMatchCountKey
;
138 const OSSymbol
* gIOServiceLegacyMatchingRegistryIDKey
;
141 const OSSymbol
* gIOMapperIDKey
;
142 const OSSymbol
* gIOUserClientClassKey
;
144 const OSSymbol
* gIOUserClassKey
;
145 const OSSymbol
* gIOUserServerClassKey
;
146 const OSSymbol
* gIOUserServerNameKey
;
147 const OSSymbol
* gIOUserServerTagKey
;
148 const OSSymbol
* gIOUserServerCDHashKey
;
149 const OSSymbol
* gIOUserUserClientKey
;
151 const OSSymbol
* gIOKitDebugKey
;
153 const OSSymbol
* gIOCommandPoolSizeKey
;
155 const OSSymbol
* gIOConsoleLockedKey
;
156 const OSSymbol
* gIOConsoleUsersKey
;
157 const OSSymbol
* gIOConsoleSessionUIDKey
;
158 const OSSymbol
* gIOConsoleSessionAuditIDKey
;
159 const OSSymbol
* gIOConsoleUsersSeedKey
;
160 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
161 const OSSymbol
* gIOConsoleSessionLoginDoneKey
;
162 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
163 const OSSymbol
* gIOConsoleSessionScreenLockedTimeKey
;
164 const OSSymbol
* gIOConsoleSessionScreenIsLockedKey
;
165 clock_sec_t gIOConsoleLockTime
;
166 static bool gIOConsoleLoggedIn
;
168 static OSBoolean
* gIOConsoleBooterLockState
;
169 static uint32_t gIOScreenLockState
;
171 static IORegistryEntry
* gIOChosenEntry
;
173 static int gIOResourceGenerationCount
;
175 const OSSymbol
* gIOServiceKey
;
176 const OSSymbol
* gIOPublishNotification
;
177 const OSSymbol
* gIOFirstPublishNotification
;
178 const OSSymbol
* gIOMatchedNotification
;
179 const OSSymbol
* gIOFirstMatchNotification
;
180 const OSSymbol
* gIOTerminatedNotification
;
181 const OSSymbol
* gIOWillTerminateNotification
;
183 const OSSymbol
* gIOServiceDEXTEntitlementsKey
;
184 const OSSymbol
* gIODriverKitEntitlementKey
;
185 const OSSymbol
* gIODriverKitUserClientEntitlementsKey
;
186 const OSSymbol
* gIOMatchDeferKey
;
188 const OSSymbol
* gIOGeneralInterest
;
189 const OSSymbol
* gIOBusyInterest
;
190 const OSSymbol
* gIOAppPowerStateInterest
;
191 const OSSymbol
* gIOPriorityPowerStateInterest
;
192 const OSSymbol
* gIOConsoleSecurityInterest
;
194 const OSSymbol
* gIOBSDKey
;
195 const OSSymbol
* gIOBSDNameKey
;
196 const OSSymbol
* gIOBSDMajorKey
;
197 const OSSymbol
* gIOBSDMinorKey
;
198 const OSSymbol
* gIOBSDUnitKey
;
200 const OSSymbol
* gAKSGetKey
;
201 #if defined(__i386__) || defined(__x86_64__)
202 const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
205 static OSDictionary
* gNotifications
;
206 static IORecursiveLock
* gNotificationLock
;
208 static IOService
* gIOResources
;
209 static IOService
* gIOUserResources
;
210 static IOService
* gIOServiceRoot
;
212 static OSOrderedSet
* gJobs
;
213 static semaphore_port_t gJobsSemaphore
;
214 static IOLock
* gJobsLock
;
215 static int gOutstandingJobs
;
216 static int gNumConfigThreads
;
217 static int gNumWaitingThreads
;
218 static IOLock
* gIOServiceBusyLock
;
220 bool gKextdWillTerminate
;
222 static thread_t gIOTerminateThread
;
223 static thread_t gIOTerminateWorkerThread
;
224 static UInt32 gIOTerminateWork
;
225 static OSArray
* gIOTerminatePhase2List
;
226 static OSArray
* gIOStopList
;
227 static OSArray
* gIOStopProviderList
;
228 static OSArray
* gIOFinalizeList
;
231 static OSArray
* gIOMatchDeferList
;
234 static SInt32 gIOConsoleUsersSeed
;
235 static OSData
* gIOConsoleUsersSeedValue
;
237 extern const OSSymbol
* gIODTPHandleKey
;
239 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
242 static IOLock
* gIOConsoleUsersLock
;
243 static thread_call_t gIOConsoleLockCallout
;
244 static IONotifier
* gIOServiceNullNotifier
;
246 static uint32_t gIODextRelaunchMax
= 1000;
248 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
250 #define LOCKREADNOTIFY() \
251 IORecursiveLockLock( gNotificationLock )
252 #define LOCKWRITENOTIFY() \
253 IORecursiveLockLock( gNotificationLock )
254 #define LOCKWRITE2READNOTIFY()
255 #define UNLOCKNOTIFY() \
256 IORecursiveLockUnlock( gNotificationLock )
257 #define SLEEPNOTIFY(event) \
258 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
259 #define SLEEPNOTIFYTO(event, deadline) \
260 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
261 #define WAKEUPNOTIFY(event) \
262 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
264 #define randomDelay() \
265 int del = read_processor_clock(); \
266 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
269 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
271 #define queue_element(entry, element, type, field) do { \
272 vm_address_t __ele = (vm_address_t) (entry); \
273 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
274 (element) = (type) __ele; \
277 #define iterqueue(que, elt) \
278 for (queue_entry_t elt = queue_first(que); \
279 !queue_end(que, elt); \
280 elt = queue_next(elt))
282 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
284 struct IOInterruptAccountingReporter
{
285 IOSimpleReporter
* reporter
; /* Reporter responsible for communicating the statistics */
286 IOInterruptAccountingData
* statistics
; /* The live statistics values, if any */
289 struct ArbitrationLockQueueElement
{
298 static queue_head_t gArbitrationLockQueueActive
;
299 static queue_head_t gArbitrationLockQueueWaiting
;
300 static queue_head_t gArbitrationLockQueueFree
;
301 static IOLock
* gArbitrationLockQueueLock
;
304 IOService::isInactive( void ) const
306 return 0 != (kIOServiceInactiveState
& getState());
309 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
311 #if defined(__i386__) || defined(__x86_64__)
313 // Only used by the intel implementation of
314 // IOService::requireMaxBusStall(UInt32 ns)
315 // IOService::requireMaxInterruptDelay(uint32_t ns)
316 struct CpuDelayEntry
{
317 IOService
* fService
;
323 kCpuDelayBusStall
, kCpuDelayInterrupt
,
327 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
328 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
329 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
330 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
331 static OSNumber
* sCPULatencyHolder
[kCpuNumDelayTypes
];
332 static char sCPULatencyHolderName
[kCpuNumDelayTypes
][128];
333 static OSNumber
* sCPULatencySet
[kCpuNumDelayTypes
];
336 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
338 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
340 #endif /* defined(__i386__) || defined(__x86_64__) */
342 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
344 namespace IOServicePH
346 IONotifier
* fRootNotifier
;
347 OSArray
* fUserServers
;
348 OSArray
* fUserServersWait
;
349 OSArray
* fMatchingWork
;
350 OSArray
* fMatchingDelayed
;
351 IOService
* fSystemPowerAckTo
;
352 uint32_t fSystemPowerAckRef
;
354 uint8_t fUserServerOff
;
359 void init(IOPMrootDomain
* root
);
361 IOReturn
systemPowerChange(
364 UInt32 messageType
, IOService
* service
,
365 void * messageArgument
, vm_size_t argSize
);
367 bool matchingStart(IOService
* service
);
368 void matchingEnd(IOService
* service
);
371 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
374 IOService::initialize( void )
378 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
379 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
381 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
382 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
383 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
384 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
385 gIOPropertyExistsMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyExistsMatchKey
);
386 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
387 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
388 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
390 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
391 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
392 kIODefaultMatchCategoryKey
);
393 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
394 kIOMatchedServiceCountKey
);
395 gIOMatchedPersonalityKey
= OSSymbol::withCStringNoCopy(
396 kIOMatchedPersonalityKey
);
397 gIORematchPersonalityKey
= OSSymbol::withCStringNoCopy(
398 kIORematchPersonalityKey
);
399 gIORematchCountKey
= OSSymbol::withCStringNoCopy(
400 kIORematchCountKey
);
401 gIODEXTMatchCountKey
= OSSymbol::withCStringNoCopy(
402 kIODEXTMatchCountKey
);
405 gIOServiceLegacyMatchingRegistryIDKey
= OSSymbol::withCStringNoCopy(
406 kIOServiceLegacyMatchingRegistryIDKey
);
409 PE_parse_boot_argn("dextrelaunch", &gIODextRelaunchMax
, sizeof(gIODextRelaunchMax
));
411 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
413 gIOUserClassKey
= OSSymbol::withCStringNoCopy(kIOUserClassKey
);
415 gIOUserServerClassKey
= OSSymbol::withCStringNoCopy(kIOUserServerClassKey
);
416 gIOUserServerNameKey
= OSSymbol::withCStringNoCopy(kIOUserServerNameKey
);
417 gIOUserServerTagKey
= OSSymbol::withCStringNoCopy(kIOUserServerTagKey
);
418 gIOUserServerCDHashKey
= OSSymbol::withCStringNoCopy(kIOUserServerCDHashKey
);
419 gIOUserUserClientKey
= OSSymbol::withCStringNoCopy(kIOUserUserClientKey
);
421 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
422 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
423 gIOResourceMatchedKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchedKey
);
424 gIOResourceIOKitKey
= OSSymbol::withCStringNoCopy("IOKit");
426 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
427 gIOInterruptControllersKey
428 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
429 gIOInterruptSpecifiersKey
430 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
432 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
434 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
436 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
438 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
439 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
440 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
441 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
442 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
444 gIOBSDKey
= OSSymbol::withCStringNoCopy(kIOBSDKey
);
445 gIOBSDNameKey
= OSSymbol::withCStringNoCopy(kIOBSDNameKey
);
446 gIOBSDMajorKey
= OSSymbol::withCStringNoCopy(kIOBSDMajorKey
);
447 gIOBSDMinorKey
= OSSymbol::withCStringNoCopy(kIOBSDMinorKey
);
448 gIOBSDUnitKey
= OSSymbol::withCStringNoCopy(kIOBSDUnitKey
);
450 gNotifications
= OSDictionary::withCapacity( 1 );
451 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
452 kIOPublishNotification
);
453 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
454 kIOFirstPublishNotification
);
455 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
456 kIOMatchedNotification
);
457 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
458 kIOFirstMatchNotification
);
459 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
460 kIOTerminatedNotification
);
461 gIOWillTerminateNotification
= OSSymbol::withCStringNoCopy(
462 kIOWillTerminateNotification
);
463 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
466 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
467 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
468 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
469 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
471 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
472 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
473 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
474 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
475 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
476 gIOConsoleSessionScreenIsLockedKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenIsLockedKey
);
478 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
480 gIOServiceDEXTEntitlementsKey
= OSSymbol::withCStringNoCopy( kIOServiceDEXTEntitlementsKey
);
481 gIODriverKitEntitlementKey
= OSSymbol::withCStringNoCopy( kIODriverKitEntitlementKey
);
482 gIODriverKitUserClientEntitlementsKey
= OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementsKey
);
483 gIOMatchDeferKey
= OSSymbol::withCStringNoCopy( kIOMatchDeferKey
);
485 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
486 #if defined(__i386__) || defined(__x86_64__)
487 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
488 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
490 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++) {
491 sCPULatencySet
[idx
] = OSNumber::withNumber(-1U, 32);
492 sCPULatencyHolder
[idx
] = OSNumber::withNumber(0ULL, 64);
493 assert(sCPULatencySet
[idx
] && sCPULatencyHolder
[idx
]);
495 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
497 gNotificationLock
= IORecursiveLockAlloc();
499 gAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
501 assert( gIOServicePlane
&& gIODeviceMemoryKey
502 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
503 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
504 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
505 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
506 && gIOPublishNotification
&& gIOMatchedNotification
507 && gIOTerminatedNotification
&& gIOServiceKey
508 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
509 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
510 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
512 gJobsLock
= IOLockAlloc();
513 gJobs
= OSOrderedSet::withCapacity( 10 );
515 gIOServiceBusyLock
= IOLockAlloc();
517 gIOConsoleUsersLock
= IOLockAlloc();
519 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
521 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
523 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
525 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
526 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
));
528 gIOResources
= IOResources::resources();
529 gIOUserResources
= IOUserResources::resources();
530 assert( gIOResources
&& gIOUserResources
);
532 gIOServiceNullNotifier
= OSTypeAlloc(_IOServiceNullNotifier
);
533 assert(gIOServiceNullNotifier
);
535 gArbitrationLockQueueLock
= IOLockAlloc();
536 queue_init(&gArbitrationLockQueueActive
);
537 queue_init(&gArbitrationLockQueueWaiting
);
538 queue_init(&gArbitrationLockQueueFree
);
540 assert( gArbitrationLockQueueLock
);
542 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
543 gIOStopList
= OSArray::withCapacity( 16 );
544 gIOStopProviderList
= OSArray::withCapacity( 16 );
545 gIOFinalizeList
= OSArray::withCapacity( 16 );
547 gIOMatchDeferList
= OSArray::withCapacity( 16 );
549 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
551 // worker thread that is responsible for terminating / cleaning up threads
552 kernel_thread_start(&terminateThread
, NULL
, &gIOTerminateWorkerThread
);
553 assert(gIOTerminateWorkerThread
);
554 thread_set_thread_name(gIOTerminateWorkerThread
, "IOServiceTerminateThread");
557 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
559 #if defined(__i386__) || defined(__x86_64__)
561 const char *getCpuDelayBusStallHolderName(void);
563 getCpuDelayBusStallHolderName(void)
565 return sCPULatencyHolderName
[kCpuDelayBusStall
];
568 const char *getCpuInterruptDelayHolderName(void);
570 getCpuInterruptDelayHolderName(void)
572 return sCPULatencyHolderName
[kCpuDelayInterrupt
];
579 getDebugFlags( OSDictionary
* props
)
581 OSNumber
* debugProp
;
584 debugProp
= OSDynamicCast( OSNumber
,
585 props
->getObject( gIOKitDebugKey
));
587 debugFlags
= debugProp
->unsigned64BitValue();
589 debugFlags
= gIOKitDebug
;
596 getDebugFlags( IOService
* inst
)
599 OSNumber
* debugProp
;
602 prop
= inst
->copyProperty(gIOKitDebugKey
);
603 debugProp
= OSDynamicCast(OSNumber
, prop
);
605 debugFlags
= debugProp
->unsigned64BitValue();
607 debugFlags
= gIOKitDebug
;
610 OSSafeReleaseNULL(prop
);
616 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
618 // Probe a matched service and return an instance to be started.
619 // The default score is from the property table, & may be altered
620 // during probe to change the start order.
623 IOService::probe( IOService
* provider
,
630 IOService::start( IOService
* provider
)
636 IOService::stop( IOService
* provider
)
638 if (reserved
->uvars
&& reserved
->uvars
->started
&& reserved
->uvars
->userServer
) {
639 reserved
->uvars
->userServer
->serviceStop(this, provider
);
644 IOService::init( OSDictionary
* dictionary
)
648 ret
= super::init(dictionary
);
656 reserved
= IONew(ExpansionData
, 1);
660 bzero(reserved
, sizeof(*reserved
));
663 * TODO: Improve on this. Previous efforts to more lazily allocate this
664 * lock based on the presence of specifiers ran into issues as some
665 * platforms set up the specifiers after IOService initialization.
667 * We may be able to get away with a global lock, as this should only be
668 * contended by IOReporting clients and driver start/stop (unless a
669 * driver wants to remove/add handlers in the course of normal operation,
670 * which should be unlikely).
672 reserved
->interruptStatisticsLock
= IOLockAlloc();
673 if (!reserved
->interruptStatisticsLock
) {
681 IOService::init( IORegistryEntry
* from
,
682 const IORegistryPlane
* inPlane
)
686 ret
= super::init(from
, inPlane
);
694 reserved
= IONew(ExpansionData
, 1);
698 bzero(reserved
, sizeof(*reserved
));
701 * TODO: Improve on this. Previous efforts to more lazily allocate this
702 * lock based on the presence of specifiers ran into issues as some
703 * platforms set up the specifiers after IOService initialization.
705 * We may be able to get away with a global lock, as this should only be
706 * contended by IOReporting clients and driver start/stop (unless a
707 * driver wants to remove/add handlers in the course of normal operation,
708 * which should be unlikely).
710 reserved
->interruptStatisticsLock
= IOLockAlloc();
711 if (!reserved
->interruptStatisticsLock
) {
719 IOService::free( void )
722 requireMaxBusStall(0);
723 requireMaxInterruptDelay(0);
724 if (getPropertyTable()) {
725 unregisterAllInterest();
730 if (reserved
->interruptStatisticsArray
) {
731 for (i
= 0; i
< reserved
->interruptStatisticsArrayCount
; i
++) {
732 if (reserved
->interruptStatisticsArray
[i
].reporter
) {
733 reserved
->interruptStatisticsArray
[i
].reporter
->release();
737 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
740 if (reserved
->interruptStatisticsLock
) {
741 IOLockFree(reserved
->interruptStatisticsLock
);
743 if (reserved
->uvars
&& reserved
->uvars
->userServer
) {
744 reserved
->uvars
->userServer
->serviceFree(this);
746 IODelete(reserved
, ExpansionData
, 1);
749 if (_numInterruptSources
&& _interruptSources
) {
750 for (i
= 0; i
< _numInterruptSources
; i
++) {
751 void * block
= _interruptSourcesPrivate(this)[i
].vectorBlock
;
753 Block_release(block
);
756 IOFree(_interruptSources
,
757 _numInterruptSources
* sizeofAllIOInterruptSource
);
758 _interruptSources
= NULL
;
765 * Attach in service plane
768 IOService::attach( IOService
* provider
)
772 AbsoluteTime deadline
;
773 int waitResult
= THREAD_AWAKENED
;
774 bool wait
, computeDeadline
= true;
777 if (gIOKitDebug
& kIOLogAttach
) {
778 LOG( "%s::attach(%s)\n", getName(),
779 provider
->getName());
785 provider
->lockForArbitration();
786 if (provider
->__state
[0] & kIOServiceInactiveState
) {
789 count
= provider
->getChildCount(gIOServicePlane
);
790 wait
= (count
> (kIOServiceBusyMax
- 4));
792 ok
= attachToParent(provider
, gIOServicePlane
);
794 IOLog("stalling for detach from %s\n", provider
->getName());
795 IOLockLock( gIOServiceBusyLock
);
796 provider
->__state
[1] |= kIOServiceWaitDetachState
;
799 provider
->unlockForArbitration();
801 if (computeDeadline
) {
802 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
803 computeDeadline
= false;
805 assert_wait_deadline((event_t
)&provider
->__provider
, THREAD_UNINT
, deadline
);
806 IOLockUnlock( gIOServiceBusyLock
);
807 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
808 wait
= (waitResult
!= THREAD_TIMED_OUT
);
812 gIOServiceRoot
= this;
813 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
816 if (ok
&& !__provider
) {
817 (void) getProvider();
824 IOService::getServiceRoot( void )
826 return gIOServiceRoot
;
830 IOService::detach( IOService
* provider
)
832 IOService
* newProvider
= NULL
;
836 if (gIOKitDebug
& kIOLogAttach
) {
837 LOG("%s::detach(%s)\n", getName(), provider
->getName());
841 IOLockLock(gJobsLock
);
842 if (gIOMatchDeferList
) {
843 auto idx
= gIOMatchDeferList
->getNextIndexOfObject(this, 0);
845 gIOMatchDeferList
->removeObject(idx
);
848 if (IOServicePH::fMatchingDelayed
) {
849 auto idx
= IOServicePH::fMatchingDelayed
->getNextIndexOfObject(this, 0);
851 IOServicePH::fMatchingDelayed
->removeObject(idx
);
854 IOLockUnlock(gJobsLock
);
855 #endif /* NO_KEXTD */
857 lockForArbitration();
859 uint64_t regID1
= provider
->getRegistryEntryID();
860 uint64_t regID2
= getRegistryEntryID();
864 (uintptr_t) (regID1
>> 32),
866 (uintptr_t) (regID2
>> 32));
868 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
869 && (provider
== getProvider()));
871 detachFromParent( provider
, gIOServicePlane
);
874 newProvider
= getProvider();
875 if (busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (NULL
== newProvider
)) {
876 _adjustBusy( -busy
);
880 if (kIOServiceInactiveState
& __state
[0]) {
881 getMetaClass()->removeInstance(this);
882 IORemoveServicePlatformActions(this);
885 unlockForArbitration();
887 if (newProvider
&& adjParent
) {
888 newProvider
->lockForArbitration();
889 newProvider
->_adjustBusy(1);
890 newProvider
->unlockForArbitration();
893 // check for last client detach from a terminated service
894 if (provider
->lockForArbitration( true )) {
895 if (kIOServiceStartState
& __state
[1]) {
896 provider
->scheduleTerminatePhase2();
899 provider
->_adjustBusy( -1 );
901 if ((provider
->__state
[1] & kIOServiceTermPhase3State
)
902 && (NULL
== provider
->getClient())) {
903 provider
->scheduleFinalize(false);
906 IOLockLock( gIOServiceBusyLock
);
907 if (kIOServiceWaitDetachState
& provider
->__state
[1]) {
908 provider
->__state
[1] &= ~kIOServiceWaitDetachState
;
909 thread_wakeup(&provider
->__provider
);
911 IOLockUnlock( gIOServiceBusyLock
);
913 provider
->unlockForArbitration();
918 * Register instance - publish it for matching
922 IOService::registerService( IOOptionBits options
)
928 enum { kMaxPathLen
= 256 };
929 enum { kMaxChars
= 63 };
931 IORegistryEntry
* parent
= this;
932 IORegistryEntry
* root
= getRegistryRoot();
933 while (parent
&& (parent
!= root
)) {
934 parent
= parent
->getParentEntry( gIOServicePlane
);
937 if (parent
!= root
) {
938 IOLog("%s: not registry member at registerService()\n", getName());
942 // Allow the Platform Expert to adjust this node.
943 if (gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this))) {
947 IOInstallServicePlatformActions(this);
949 if ((this != gIOResources
)
950 && (kIOLogRegister
& gIOKitDebug
)) {
951 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
953 IOLog( "Registering: " );
956 if (pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
958 if (len
> kMaxChars
) {
962 if ((skip
= strchr( path
, '/'))) {
970 IOLog( "%s\n", path
);
973 IOFree( pathBuf
, kMaxPathLen
);
977 startMatching( options
);
981 IOService::startMatching( IOOptionBits options
)
983 IOService
* provider
;
986 bool needWake
= false;
991 lockForArbitration();
993 sync
= (options
& kIOServiceSynchronous
)
994 || ((provider
= getProvider())
995 && (provider
->__state
[1] & kIOServiceSynchronousState
));
997 if (options
& kIOServiceAsynchronous
) {
1001 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigRunning
)))
1002 && (0 == (__state
[0] & kIOServiceInactiveState
));
1004 __state
[1] |= kIOServiceNeedConfigState
;
1006 // __state[0] &= ~kIOServiceInactiveState;
1008 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
1009 // OSKernelStackRemaining(), getName());
1012 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
1016 __state
[1] |= kIOServiceSynchronousState
;
1018 __state
[1] &= ~kIOServiceSynchronousState
;
1022 prevBusy
= _adjustBusy( 1 );
1025 unlockForArbitration();
1029 IOLockLock( gIOServiceBusyLock
);
1030 thread_wakeup((event_t
) this /*&__state[1]*/ );
1031 IOLockUnlock( gIOServiceBusyLock
);
1032 } else if (!sync
|| (kIOServiceAsynchronous
& options
)) {
1033 ok
= (NULL
!= _IOServiceJob::startJob( this, kMatchNubJob
, options
));
1036 if ((__state
[1] & kIOServiceNeedConfigState
)) {
1037 doServiceMatch( options
);
1040 lockForArbitration();
1041 IOLockLock( gIOServiceBusyLock
);
1043 waitAgain
= ((prevBusy
< (__state
[1] & kIOServiceBusyStateMask
))
1044 && (0 == (__state
[0] & kIOServiceInactiveState
)));
1047 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
1049 __state
[1] &= ~kIOServiceSyncPubState
;
1052 unlockForArbitration();
1055 assert_wait((event_t
) this /*&__state[1]*/, THREAD_UNINT
);
1058 IOLockUnlock( gIOServiceBusyLock
);
1060 thread_block(THREAD_CONTINUE_NULL
);
1062 } while (waitAgain
);
1069 IOService::startDeferredMatches(void)
1074 IOLockLock(gJobsLock
);
1075 array
= gIOMatchDeferList
;
1076 gIOMatchDeferList
= NULL
;
1077 IOLockUnlock(gJobsLock
);
1080 IOLog("deferred rematching count %d\n", array
->getCount());
1081 array
->iterateObjects(^bool (OSObject
* obj
)
1083 ((IOService
*)obj
)->startMatching(kIOServiceAsynchronous
);
1088 #endif /* !NO_KEXTD */
1092 IOService::kextdLaunched(void)
1095 IOServiceTrace(IOSERVICE_KEXTD_READY
, 0, 0, 0, 0);
1096 startDeferredMatches();
1097 getServiceRoot()->adjustBusy(-1);
1098 IOService::publishUserResource(gIOResourceIOKitKey
);
1099 #endif /* !NO_KEXTD */
1103 IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
1105 OSDictionary
* table
;
1107 OSSet
* allSet
= NULL
;
1108 IOService
* service
;
1113 newTables
->retain();
1115 while ((table
= (OSDictionary
*) newTables
->getFirstObject())) {
1117 set
= (OSSet
*) copyExistingServices( table
,
1118 kIOServiceRegisteredState
,
1119 kIOServiceExistingSet
);
1123 count
+= set
->getCount();
1126 allSet
->merge((const OSSet
*) set
);
1134 if (getDebugFlags( table
) & kIOLogMatch
) {
1135 LOG("Matching service count = %ld\n", (long)count
);
1138 newTables
->removeObject(table
);
1142 while ((service
= (IOService
*) allSet
->getAnyObject())) {
1143 service
->startMatching(kIOServiceAsynchronous
);
1144 allSet
->removeObject(service
);
1149 newTables
->release();
1151 return kIOReturnSuccess
;
1155 _IOServiceJob::startJob( IOService
* nub
, int type
,
1156 IOOptionBits options
)
1158 _IOServiceJob
* job
;
1160 job
= new _IOServiceJob
;
1161 if (job
&& !job
->init()) {
1169 job
->options
= options
;
1170 nub
->retain(); // thread will release()
1178 * Called on a registered service to see if it matches
1183 IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
1185 return matchPropertyTable(table
);
1189 IOService::matchPropertyTable( OSDictionary
* table
)
1195 * Called on a matched service to allocate resources
1196 * before first driver is attached.
1200 IOService::getResources( void )
1202 return kIOReturnSuccess
;
1206 * Client/provider accessors
1210 IOService::getProvider( void ) const
1212 IOService
* self
= (IOService
*) this;
1216 generation
= getRegistryEntryGenerationCount();
1217 if (__providerGeneration
== generation
) {
1221 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
1222 if (parent
== IORegistryEntry::getRegistryRoot()) {
1223 /* root is not an IOService */
1227 self
->__provider
= parent
;
1229 // save the count from before call to getParentEntry()
1230 self
->__providerGeneration
= generation
;
1236 IOService::getWorkLoop() const
1238 IOService
*provider
= getProvider();
1241 return provider
->getWorkLoop();
1248 IOService::getProviderIterator( void ) const
1250 return getParentIterator( gIOServicePlane
);
1254 IOService::getClient( void ) const
1256 return (IOService
*) getChildEntry( gIOServicePlane
);
1260 IOService::getClientIterator( void ) const
1262 return getChildIterator( gIOServicePlane
);
1266 _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
1267 const IOService
* client
,
1268 const IOService
* provider
)
1270 _IOOpenServiceIterator
* inst
;
1276 inst
= new _IOOpenServiceIterator
;
1278 if (inst
&& !inst
->init()) {
1284 inst
->client
= client
;
1285 inst
->provider
= provider
;
1292 _IOOpenServiceIterator::free()
1296 last
->unlockForArbitration();
1302 _IOOpenServiceIterator::getNextObject()
1307 last
->unlockForArbitration();
1310 while ((next
= (IOService
*) iter
->getNextObject())) {
1311 next
->lockForArbitration();
1312 if ((client
&& (next
->isOpen( client
)))
1313 || (provider
&& (provider
->isOpen( next
)))) {
1316 next
->unlockForArbitration();
1325 _IOOpenServiceIterator::isValid()
1327 return iter
->isValid();
1331 _IOOpenServiceIterator::reset()
1334 last
->unlockForArbitration();
1341 IOService::getOpenProviderIterator( void ) const
1343 return _IOOpenServiceIterator::iterator( getProviderIterator(), this, NULL
);
1347 IOService::getOpenClientIterator( void ) const
1349 return _IOOpenServiceIterator::iterator( getClientIterator(), NULL
, this );
1354 IOService::callPlatformFunction( const OSSymbol
* functionName
,
1355 bool waitForFunction
,
1356 void *param1
, void *param2
,
1357 void *param3
, void *param4
)
1359 IOReturn result
= kIOReturnUnsupported
;
1360 IOService
*provider
;
1362 if (functionName
== gIOPlatformQuiesceActionKey
||
1363 functionName
== gIOPlatformActiveActionKey
) {
1365 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
1366 * must consume that event themselves, without passing it up to super/IOService.
1368 if (gEnforceQuiesceSafety
) {
1369 panic("Class %s passed the quiesce/active action to IOService",
1370 getMetaClass()->getClassName());
1374 if (gIOPlatformFunctionHandlerSet
== functionName
) {
1375 #if defined(__i386__) || defined(__x86_64__)
1376 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
1377 IOService
* target
= (IOService
*) param2
;
1378 bool enable
= (param3
!= NULL
);
1380 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
) {
1381 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
1382 } else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
) {
1383 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
1385 #endif /* defined(__i386__) || defined(__x86_64__) */
1388 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
1389 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
1390 param1
, param2
, param3
, param4
);
1397 IOService::callPlatformFunction( const char * functionName
,
1398 bool waitForFunction
,
1399 void *param1
, void *param2
,
1400 void *param3
, void *param4
)
1402 IOReturn result
= kIOReturnNoMemory
;
1403 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
1405 if (functionSymbol
!= NULL
) {
1406 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
1407 param1
, param2
, param3
, param4
);
1408 functionSymbol
->release();
1416 * Accessors for global services
1420 IOService::getPlatform( void )
1425 class IOPMrootDomain
*
1426 IOService::getPMRootDomain( void )
1428 return gIOPMRootDomain
;
1432 IOService::getResourceService( void )
1434 return gIOResources
;
1438 IOService::setPlatform( IOPlatformExpert
* platform
)
1440 gIOPlatform
= platform
;
1441 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1442 gIOUserResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1444 #if defined(__i386__) || defined(__x86_64__)
1446 static const char * keys
[kCpuNumDelayTypes
] = {
1447 kIOPlatformMaxBusDelay
, kIOPlatformMaxInterruptDelay
};
1448 const OSObject
* objs
[2];
1452 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++) {
1453 objs
[0] = sCPULatencySet
[idx
];
1454 objs
[1] = sCPULatencyHolder
[idx
];
1455 array
= OSArray::withObjects(objs
, 2);
1459 platform
->setProperty(keys
[idx
], array
);
1462 #endif /* defined(__i386__) || defined(__x86_64__) */
1466 IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
1468 gIOPMRootDomain
= rootDomain
;
1469 publishResource(gIOResourceIOKitKey
);
1470 IOServicePH::init(rootDomain
);
1478 IOService::lockForArbitration( bool isSuccessRequired
)
1482 ArbitrationLockQueueElement
* element
;
1483 ArbitrationLockQueueElement
* active
;
1484 ArbitrationLockQueueElement
* waiting
;
1486 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
1488 // lock global access
1489 IOTakeLock( gArbitrationLockQueueLock
);
1491 // obtain an unused queue element
1492 if (!queue_empty( &gArbitrationLockQueueFree
)) {
1493 queue_remove_first( &gArbitrationLockQueueFree
,
1495 ArbitrationLockQueueElement
*,
1498 element
= IONew( ArbitrationLockQueueElement
, 1 );
1502 // prepare the queue element
1503 element
->thread
= IOThreadSelf();
1504 element
->service
= this;
1506 element
->required
= isSuccessRequired
;
1507 element
->aborted
= false;
1509 // determine whether this object is already locked (ie. on active queue)
1511 queue_iterate( &gArbitrationLockQueueActive
,
1513 ArbitrationLockQueueElement
*,
1516 if (active
->service
== element
->service
) {
1522 if (found
) { // this object is already locked
1523 // determine whether it is the same or a different thread trying to lock
1524 if (active
->thread
!= element
->thread
) { // it is a different thread
1525 ArbitrationLockQueueElement
* victim
= NULL
;
1527 // before placing this new thread on the waiting queue, we look for
1528 // a deadlock cycle...
1531 // determine whether the active thread holding the object we
1532 // want is waiting for another object to be unlocked
1534 queue_iterate( &gArbitrationLockQueueWaiting
,
1536 ArbitrationLockQueueElement
*,
1539 if (waiting
->thread
== active
->thread
) {
1540 assert( false == waiting
->aborted
);
1546 if (found
) { // yes, active thread waiting for another object
1547 // this may be a candidate for rejection if the required
1548 // flag is not set, should we detect a deadlock later on
1549 if (false == waiting
->required
) {
1553 // find the thread that is holding this other object, that
1554 // is blocking the active thread from proceeding (fun :-)
1556 queue_iterate( &gArbitrationLockQueueActive
,
1557 active
, // (reuse active queue element)
1558 ArbitrationLockQueueElement
*,
1561 if (active
->service
== waiting
->service
) {
1567 // someone must be holding it or it wouldn't be waiting
1570 if (active
->thread
== element
->thread
) {
1571 // doh, it's waiting for the thread that originated
1572 // this whole lock (ie. current thread) -> deadlock
1573 if (false == element
->required
) { // willing to fail?
1574 // the originating thread doesn't have the required
1575 // flag, so it can fail
1576 success
= false; // (fail originating lock request)
1577 break; // (out of while)
1578 } else { // originating thread is not willing to fail
1579 // see if we came across a waiting thread that did
1580 // not have the 'required' flag set: we'll fail it
1582 // we do have a willing victim, fail it's lock
1583 victim
->aborted
= true;
1585 // take the victim off the waiting queue
1586 queue_remove( &gArbitrationLockQueueWaiting
,
1588 ArbitrationLockQueueElement
*,
1592 IOLockWakeup( gArbitrationLockQueueLock
,
1594 /* one thread */ true );
1596 // allow this thread to proceed (ie. wait)
1597 success
= true; // (put request on wait queue)
1598 break; // (out of while)
1600 // all the waiting threads we came across in
1601 // finding this loop had the 'required' flag
1602 // set, so we've got a deadlock we can't avoid
1603 panic("I/O Kit: Unrecoverable deadlock.");
1607 // repeat while loop, redefining active thread to be the
1608 // thread holding "this other object" (see above), and
1609 // looking for threads waiting on it; note the active
1610 // variable points to "this other object" already... so
1611 // there nothing to do in this else clause.
1613 } else { // no, active thread is not waiting for another object
1614 success
= true; // (put request on wait queue)
1615 break; // (out of while)
1619 if (success
) { // put the request on the waiting queue?
1620 kern_return_t wait_result
;
1622 // place this thread on the waiting queue and put it to sleep;
1623 // we place it at the tail of the queue...
1624 queue_enter( &gArbitrationLockQueueWaiting
,
1626 ArbitrationLockQueueElement
*,
1629 // declare that this thread will wait for a given event
1630 restart_sleep
: wait_result
= assert_wait( element
,
1631 element
->required
? THREAD_UNINT
1632 : THREAD_INTERRUPTIBLE
);
1634 // unlock global access
1635 IOUnlock( gArbitrationLockQueueLock
);
1637 // put thread to sleep, waiting for our event to fire...
1638 if (wait_result
== THREAD_WAITING
) {
1639 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1643 // ...and we've been woken up; we might be in one of two states:
1644 // (a) we've been aborted and our queue element is not on
1645 // any of the three queues, but is floating around
1646 // (b) we're allowed to proceed with the lock and we have
1647 // already been moved from the waiting queue to the
1649 // ...plus a 3rd state, should the thread have been interrupted:
1650 // (c) we're still on the waiting queue
1652 // determine whether we were interrupted out of our sleep
1653 if (THREAD_INTERRUPTED
== wait_result
) {
1654 // re-lock global access
1655 IOTakeLock( gArbitrationLockQueueLock
);
1657 // determine whether we're still on the waiting queue
1659 queue_iterate( &gArbitrationLockQueueWaiting
,
1660 waiting
, // (reuse waiting queue element)
1661 ArbitrationLockQueueElement
*,
1664 if (waiting
== element
) {
1670 if (found
) { // yes, we're still on the waiting queue
1671 // determine whether we're willing to fail
1672 if (false == element
->required
) {
1673 // mark us as aborted
1674 element
->aborted
= true;
1676 // take us off the waiting queue
1677 queue_remove( &gArbitrationLockQueueWaiting
,
1679 ArbitrationLockQueueElement
*,
1681 } else { // we are not willing to fail
1682 // ignore interruption, go back to sleep
1687 // unlock global access
1688 IOUnlock( gArbitrationLockQueueLock
);
1690 // proceed as though this were a normal wake up
1691 wait_result
= THREAD_AWAKENED
;
1694 assert( THREAD_AWAKENED
== wait_result
);
1696 // determine whether we've been aborted while we were asleep
1697 if (element
->aborted
) {
1698 assert( false == element
->required
);
1700 // re-lock global access
1701 IOTakeLock( gArbitrationLockQueueLock
);
1703 action
= kPutOnFreeQueue
;
1705 } else { // we weren't aborted, so we must be ready to go :-)
1706 // we've already been moved from waiting to active queue
1709 } else { // the lock request is to be failed
1710 // return unused queue element to queue
1711 action
= kPutOnFreeQueue
;
1713 } else { // it is the same thread, recursive access is allowed
1714 // add one level of recursion
1717 // return unused queue element to queue
1718 action
= kPutOnFreeQueue
;
1721 } else { // this object is not already locked, so let this thread through
1722 action
= kPutOnActiveQueue
;
1726 // put the new element on a queue
1727 if (kPutOnActiveQueue
== action
) {
1728 queue_enter( &gArbitrationLockQueueActive
,
1730 ArbitrationLockQueueElement
*,
1732 } else if (kPutOnFreeQueue
== action
) {
1733 queue_enter( &gArbitrationLockQueueFree
,
1735 ArbitrationLockQueueElement
*,
1738 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1741 // unlock global access
1742 IOUnlock( gArbitrationLockQueueLock
);
1748 IOService::unlockForArbitration( void )
1751 ArbitrationLockQueueElement
* element
;
1753 // lock global access
1754 IOTakeLock( gArbitrationLockQueueLock
);
1756 // find the lock element for this object (ie. on active queue)
1758 queue_iterate( &gArbitrationLockQueueActive
,
1760 ArbitrationLockQueueElement
*,
1763 if (element
->service
== this) {
1771 // determine whether the lock has been taken recursively
1772 if (element
->count
> 1) {
1773 // undo one level of recursion
1776 // remove it from the active queue
1777 queue_remove( &gArbitrationLockQueueActive
,
1779 ArbitrationLockQueueElement
*,
1782 // put it on the free queue
1783 queue_enter( &gArbitrationLockQueueFree
,
1785 ArbitrationLockQueueElement
*,
1788 // determine whether a thread is waiting for object (head to tail scan)
1790 queue_iterate( &gArbitrationLockQueueWaiting
,
1792 ArbitrationLockQueueElement
*,
1795 if (element
->service
== this) {
1801 if (found
) { // we found an interested thread on waiting queue
1802 // remove it from the waiting queue
1803 queue_remove( &gArbitrationLockQueueWaiting
,
1805 ArbitrationLockQueueElement
*,
1808 // put it on the active queue
1809 queue_enter( &gArbitrationLockQueueActive
,
1811 ArbitrationLockQueueElement
*,
1814 // wake the waiting thread
1815 IOLockWakeup( gArbitrationLockQueueLock
,
1817 /* one thread */ true );
1821 // unlock global access
1822 IOUnlock( gArbitrationLockQueueLock
);
1826 IOService::isLockedForArbitration(IOService
* service
)
1828 #if DEBUG_NOTIFIER_LOCKED
1830 ArbitrationLockQueueElement
* active
;
1832 // lock global access
1833 IOLockLock(gArbitrationLockQueueLock
);
1835 // determine whether this object is already locked (ie. on active queue)
1837 queue_iterate(&gArbitrationLockQueueActive
,
1839 ArbitrationLockQueueElement
*,
1842 if ((active
->thread
== IOThreadSelf())
1843 && (!service
|| (active
->service
== service
))) {
1845 count
+= active
->count
;
1849 IOLockUnlock(gArbitrationLockQueueLock
);
1853 #else /* DEBUG_NOTIFIER_LOCKED */
1857 #endif /* DEBUG_NOTIFIER_LOCKED */
1861 IOService::applyToProviders( IOServiceApplierFunction applier
,
1864 applyToParents((IORegistryEntryApplierFunction
) applier
,
1865 context
, gIOServicePlane
);
1869 IOService::applyToClients( IOServiceApplierFunction applier
,
1872 applyToChildren((IORegistryEntryApplierFunction
) applier
,
1873 context
, gIOServicePlane
);
1882 // send a message to a client or interested party of this service
1884 IOService::messageClient( UInt32 type
, OSObject
* client
,
1885 void * argument
, vm_size_t argSize
)
1888 IOService
* service
;
1889 _IOServiceInterestNotifier
* notify
;
1891 if ((service
= OSDynamicCast( IOService
, client
))) {
1892 ret
= service
->message( type
, this, argument
);
1893 } else if ((notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1894 _IOServiceNotifierInvocation invocation
;
1897 invocation
.thread
= current_thread();
1900 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1903 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1904 _IOServiceNotifierInvocation
*, link
);
1909 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1910 type
, this, argument
, argSize
);
1913 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1914 _IOServiceNotifierInvocation
*, link
);
1915 if (kIOServiceNotifyWaiter
& notify
->state
) {
1916 notify
->state
&= ~kIOServiceNotifyWaiter
;
1917 WAKEUPNOTIFY( notify
);
1921 ret
= kIOReturnSuccess
;
1924 ret
= kIOReturnBadArgument
;
1931 applyToInterestNotifiers(const IORegistryEntry
*target
,
1932 const OSSymbol
* typeOfInterest
,
1933 OSObjectApplierFunction applier
,
1936 OSArray
* copyArray
= NULL
;
1941 prop
= target
->copyProperty(typeOfInterest
);
1942 IOCommand
*notifyList
= OSDynamicCast(IOCommand
, prop
);
1945 copyArray
= OSArray::withCapacity(1);
1947 // iterate over queue, entry is set to each element in the list
1948 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1949 _IOServiceInterestNotifier
* notify
;
1951 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1952 copyArray
->setObject(notify
);
1961 for (index
= 0; (next
= copyArray
->getObject( index
)); index
++) {
1962 (*applier
)(next
, context
);
1964 copyArray
->release();
1967 OSSafeReleaseNULL(prop
);
1971 IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1972 OSObjectApplierFunction applier
,
1975 if (gIOGeneralInterest
== typeOfInterest
) {
1976 applyToClients((IOServiceApplierFunction
) applier
, context
);
1978 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1981 struct MessageClientsContext
{
1982 IOService
* service
;
1990 messageClientsApplier( OSObject
* object
, void * ctx
)
1993 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1995 ret
= context
->service
->messageClient( context
->type
,
1996 object
, context
->argument
, context
->argSize
);
1997 if (kIOReturnSuccess
!= ret
) {
2002 // send a message to all clients
2004 IOService::messageClients( UInt32 type
,
2005 void * argument
, vm_size_t argSize
)
2007 MessageClientsContext context
;
2009 context
.service
= this;
2010 context
.type
= type
;
2011 context
.argument
= argument
;
2012 context
.argSize
= argSize
;
2013 context
.ret
= kIOReturnSuccess
;
2015 applyToInterested( gIOGeneralInterest
,
2016 &messageClientsApplier
, &context
);
2022 IOService::acknowledgeNotification( IONotificationRef notification
,
2023 IOOptionBits response
)
2025 return kIOReturnUnsupported
;
2029 IOService::registerInterest( const OSSymbol
* typeOfInterest
,
2030 IOServiceInterestHandler handler
, void * target
, void * ref
)
2032 _IOServiceInterestNotifier
* notify
= NULL
;
2033 IOReturn rc
= kIOReturnError
;
2035 notify
= new _IOServiceInterestNotifier
;
2040 if (notify
->init()) {
2041 rc
= registerInterestForNotifier(notify
, typeOfInterest
,
2042 handler
, target
, ref
);
2045 if (rc
!= kIOReturnSuccess
) {
2056 IOServiceInterestHandlerToBlock( void * target __unused
, void * refCon
,
2057 UInt32 messageType
, IOService
* provider
,
2058 void * messageArgument
, vm_size_t argSize
)
2060 return ((IOServiceInterestHandlerBlock
) refCon
)(messageType
, provider
, messageArgument
, argSize
);
2064 IOService::registerInterest(const OSSymbol
* typeOfInterest
,
2065 IOServiceInterestHandlerBlock handler
)
2067 IONotifier
* notify
;
2070 block
= Block_copy(handler
);
2075 notify
= registerInterest(typeOfInterest
, &IOServiceInterestHandlerToBlock
, NULL
, block
);
2078 Block_release(block
);
2085 IOService::registerInterestForNotifier( IONotifier
*svcNotify
, const OSSymbol
* typeOfInterest
,
2086 IOServiceInterestHandler handler
, void * target
, void * ref
)
2088 IOReturn rc
= kIOReturnSuccess
;
2089 _IOServiceInterestNotifier
*notify
= NULL
;
2091 if (!svcNotify
|| !(notify
= OSDynamicCast(_IOServiceInterestNotifier
, svcNotify
))) {
2092 return kIOReturnBadArgument
;
2095 notify
->handler
= handler
;
2096 notify
->target
= target
;
2099 if ((typeOfInterest
!= gIOGeneralInterest
)
2100 && (typeOfInterest
!= gIOBusyInterest
)
2101 && (typeOfInterest
!= gIOAppPowerStateInterest
)
2102 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
2103 && (typeOfInterest
!= gIOPriorityPowerStateInterest
)) {
2104 return kIOReturnBadArgument
;
2107 lockForArbitration();
2108 if (0 == (__state
[0] & kIOServiceInactiveState
)) {
2109 notify
->state
= kIOServiceNotifyEnable
;
2115 // Get the head of the notifier linked list
2116 IOCommand
* notifyList
;
2117 OSObject
* obj
= copyProperty( typeOfInterest
);
2118 if (!(notifyList
= OSDynamicCast(IOCommand
, obj
))) {
2119 notifyList
= OSTypeAlloc(IOCommand
);
2122 bool ok
= setProperty( typeOfInterest
, notifyList
);
2123 notifyList
->release();
2134 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
2135 notify
->retain(); // ref'ed while in list
2140 rc
= kIOReturnNotReady
;
2142 unlockForArbitration();
2148 cleanInterestList( OSObject
* head
)
2150 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
2156 while (queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
)) {
2157 queue_next(entry
) = queue_prev(entry
) = NULL
;
2159 _IOServiceInterestNotifier
* notify
;
2161 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
2168 IOService::unregisterAllInterest( void )
2172 prop
= copyProperty(gIOGeneralInterest
);
2173 cleanInterestList(prop
);
2174 OSSafeReleaseNULL(prop
);
2176 prop
= copyProperty(gIOBusyInterest
);
2177 cleanInterestList(prop
);
2178 OSSafeReleaseNULL(prop
);
2180 prop
= copyProperty(gIOAppPowerStateInterest
);
2181 cleanInterestList(prop
);
2182 OSSafeReleaseNULL(prop
);
2184 prop
= copyProperty(gIOPriorityPowerStateInterest
);
2185 cleanInterestList(prop
);
2186 OSSafeReleaseNULL(prop
);
2188 prop
= copyProperty(gIOConsoleSecurityInterest
);
2189 cleanInterestList(prop
);
2190 OSSafeReleaseNULL(prop
);
2194 * _IOServiceInterestNotifier
2197 // wait for all threads, other than the current one,
2198 // to exit the handler
2201 _IOServiceInterestNotifier::wait()
2203 _IOServiceNotifierInvocation
* next
;
2208 queue_iterate( &handlerInvocations
, next
,
2209 _IOServiceNotifierInvocation
*, link
) {
2210 if (next
->thread
!= current_thread()) {
2216 state
|= kIOServiceNotifyWaiter
;
2223 _IOServiceInterestNotifier::free()
2225 assert( queue_empty( &handlerInvocations
));
2227 if (handler
== &IOServiceInterestHandlerToBlock
) {
2235 _IOServiceInterestNotifier::remove()
2239 if (queue_next( &chain
)) {
2241 queue_next( &chain
) = queue_prev( &chain
) = NULL
;
2245 state
&= ~kIOServiceNotifyEnable
;
2255 _IOServiceInterestNotifier::disable()
2261 ret
= (0 != (kIOServiceNotifyEnable
& state
));
2262 state
&= ~kIOServiceNotifyEnable
;
2273 _IOServiceInterestNotifier::enable( bool was
)
2277 state
|= kIOServiceNotifyEnable
;
2279 state
&= ~kIOServiceNotifyEnable
;
2285 _IOServiceInterestNotifier::init()
2287 queue_init( &handlerInvocations
);
2288 return OSObject::init();
2290 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2296 #define tailQ(o) setObject(o)
2297 #define headQ(o) setObject(0, o)
2298 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
2301 _workLoopAction( IOWorkLoop::Action action
,
2302 IOService
* service
,
2303 void * p0
= NULL
, void * p1
= NULL
,
2304 void * p2
= NULL
, void * p3
= NULL
)
2308 if ((wl
= service
->getWorkLoop())) {
2310 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
2313 (*action
)( service
, p0
, p1
, p2
, p3
);
2318 IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
2322 // if its our only provider
2323 ok
= isParent( provider
, gIOServicePlane
, true);
2327 provider
->terminateClient( this, options
| kIOServiceRecursing
);
2328 ok
= (0 != (kIOServiceInactiveState
& __state
[0]));
2336 IOService::terminatePhase1( IOOptionBits options
)
2340 IOService
* rematchProvider
;
2342 OSArray
* makeInactive
;
2343 OSArray
* waitingInactive
;
2344 IOOptionBits callerOptions
;
2345 int waitResult
= THREAD_AWAKENED
;
2349 bool startPhase2
= false;
2351 TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options
);
2353 callerOptions
= options
;
2354 rematchProvider
= NULL
;
2355 uint64_t regID
= getRegistryEntryID();
2357 IOSERVICE_TERMINATE_PHASE1
,
2359 (uintptr_t) (regID
>> 32),
2361 (uintptr_t) options
);
2364 if (options
& kIOServiceRecursing
) {
2365 lockForArbitration();
2366 if (0 == (kIOServiceInactiveState
& __state
[0])) {
2367 __state
[0] |= kIOServiceInactiveState
;
2368 __state
[1] |= kIOServiceRecursing
| kIOServiceTermPhase1State
;
2370 unlockForArbitration();
2376 makeInactive
= OSArray::withCapacity( 16 );
2377 waitingInactive
= OSArray::withCapacity( 16 );
2378 if (!makeInactive
|| !waitingInactive
) {
2386 didInactive
= victim
->lockForArbitration( true );
2388 uint64_t regID1
= victim
->getRegistryEntryID();
2389 IOServiceTrace(IOSERVICE_TERM_SET_INACTIVE
,
2391 (uintptr_t) (regID1
>> 32),
2392 (uintptr_t) victim
->__state
[1],
2395 enum { kRP1
= kIOServiceRecursing
| kIOServiceTermPhase1State
};
2396 didInactive
= (kRP1
== (victim
->__state
[1] & kRP1
))
2397 || (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
2400 // a multiply attached IOService can be visited twice
2401 if (-1U == waitingInactive
->getNextIndexOfObject(victim
, 0)) {
2403 IOLockLock(gIOServiceBusyLock
);
2404 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
2406 TLOG("%s[0x%qx]::waitPhase1(%s[0x%qx])\n",
2407 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2408 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
2409 victim
->unlockForArbitration();
2410 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
2412 IOLockUnlock(gIOServiceBusyLock
);
2414 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2415 TLOG("%s[0x%qx]::did waitPhase1(%s[0x%qx])\n",
2416 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2417 victim
->lockForArbitration();
2419 }while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2422 victim
->__state
[0] |= kIOServiceInactiveState
;
2423 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
2424 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
2425 victim
->__state
[1] &= ~kIOServiceRecursing
;
2426 victim
->__state
[1] |= kIOServiceTermPhase1State
;
2427 waitingInactive
->headQ(victim
);
2428 if (victim
== this) {
2429 if (kIOServiceTerminateNeedWillTerminate
& options
) {
2430 victim
->__state
[1] |= kIOServiceNeedWillTerminate
;
2433 victim
->_adjustBusy( 1 );
2435 if ((options
& kIOServiceTerminateWithRematch
) && (victim
== this)) {
2437 OSObject
* rematchProps
;
2441 rematchProvider
= getProvider();
2442 if (rematchProvider
) {
2443 obj
= rematchProvider
->copyProperty(gIORematchCountKey
);
2444 num
= OSDynamicCast(OSNumber
, obj
);
2447 count
= num
->unsigned32BitValue();
2450 num
= OSNumber::withNumber(count
, 32);
2451 rematchProvider
->setProperty(gIORematchCountKey
, num
);
2452 rematchProps
= copyProperty(gIOMatchedPersonalityKey
);
2453 rematchProvider
->setProperty(gIORematchPersonalityKey
, rematchProps
);
2454 OSSafeReleaseNULL(num
);
2455 OSSafeReleaseNULL(rematchProps
);
2456 OSSafeReleaseNULL(obj
);
2460 victim
->unlockForArbitration();
2462 if (victim
== this) {
2463 options
&= ~kIOServiceTerminateWithRematch
;
2464 startPhase2
= didInactive
;
2467 OSArray
* notifiers
;
2468 notifiers
= victim
->copyNotifiers(gIOTerminatedNotification
, 0, 0xffffffff);
2469 victim
->invokeNotifiers(¬ifiers
);
2471 IOUserClient::destroyUserReferences( victim
);
2473 iter
= victim
->getClientIterator();
2475 while ((client
= (IOService
*) iter
->getNextObject())) {
2476 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n",
2477 client
->getName(), client
->getRegistryEntryID(),
2478 victim
->getName(), victim
->getRegistryEntryID(), (long long)options
);
2479 ok
= client
->requestTerminate( victim
, options
);
2480 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n",
2481 client
->getName(), client
->getRegistryEntryID(),
2482 victim
->getName(), victim
->getRegistryEntryID(), ok
);
2484 uint64_t regID1
= client
->getRegistryEntryID();
2485 uint64_t regID2
= victim
->getRegistryEntryID();
2487 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
2488 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
2490 (uintptr_t) (regID1
>> 32),
2492 (uintptr_t) (regID2
>> 32));
2495 makeInactive
->setObject( client
);
2502 victim
= (IOService
*) makeInactive
->getObject(0);
2505 makeInactive
->removeObject(0);
2508 makeInactive
->release();
2510 while ((victim
= (IOService
*) waitingInactive
->getObject(0))) {
2512 waitingInactive
->removeObject(0);
2514 victim
->lockForArbitration();
2515 victim
->__state
[1] &= ~kIOServiceTermPhase1State
;
2516 if (kIOServiceTerm1WaiterState
& victim
->__state
[1]) {
2517 victim
->__state
[1] &= ~kIOServiceTerm1WaiterState
;
2518 TLOG("%s[0x%qx]::wakePhase1\n", victim
->getName(), victim
->getRegistryEntryID());
2519 IOLockLock( gIOServiceBusyLock
);
2520 thread_wakeup((event_t
) &victim
->__state
[1]);
2521 IOLockUnlock( gIOServiceBusyLock
);
2523 victim
->unlockForArbitration();
2526 waitingInactive
->release();
2530 lockForArbitration();
2531 scheduleTerminatePhase2(options
);
2532 unlockForArbitration();
2536 if (rematchProvider
) {
2537 DKLOG(DKS
" rematching after dext crash\n", DKN(rematchProvider
));
2538 rematchProvider
->registerService();
2545 IOService::setTerminateDefer(IOService
* provider
, bool defer
)
2547 lockForArbitration();
2549 __state
[1] |= kIOServiceStartState
;
2551 __state
[1] &= ~kIOServiceStartState
;
2553 unlockForArbitration();
2555 if (provider
&& !defer
) {
2556 provider
->lockForArbitration();
2557 provider
->scheduleTerminatePhase2();
2558 provider
->unlockForArbitration();
2562 // Must call this while holding gJobsLock
2564 IOService::waitToBecomeTerminateThread(void)
2566 IOLockAssert(gJobsLock
, kIOLockAssertOwned
);
2569 wait
= (gIOTerminateThread
!= THREAD_NULL
);
2571 IOLockSleep(gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
2574 gIOTerminateThread
= current_thread();
2577 // call with lockForArbitration
2579 IOService::scheduleTerminatePhase2( IOOptionBits options
)
2581 AbsoluteTime deadline
;
2583 int waitResult
= THREAD_AWAKENED
;
2584 bool wait
= false, haveDeadline
= false;
2586 if (!(__state
[0] & kIOServiceInactiveState
)) {
2590 regID1
= getRegistryEntryID();
2592 IOSERVICE_TERM_SCHED_PHASE2
,
2594 (uintptr_t) (regID1
>> 32),
2595 (uintptr_t) __state
[1],
2596 (uintptr_t) options
);
2598 if (__state
[1] & kIOServiceTermPhase1State
) {
2603 unlockForArbitration();
2604 options
|= kIOServiceRequired
;
2605 IOLockLock( gJobsLock
);
2607 if ((options
& kIOServiceSynchronous
)
2608 && (current_thread() != gIOTerminateThread
)) {
2609 waitToBecomeTerminateThread();
2610 gIOTerminatePhase2List
->setObject( this );
2614 while (gIOTerminateWork
) {
2615 terminateWorker( options
);
2617 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
2619 /* wait for the victim to go non-busy */
2620 if (!haveDeadline
) {
2621 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
2622 haveDeadline
= true;
2624 /* let others do work while we wait */
2625 gIOTerminateThread
= NULL
;
2626 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2627 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
2628 deadline
, THREAD_UNINT
);
2629 if (__improbable(waitResult
== THREAD_TIMED_OUT
)) {
2630 IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous): THREAD_TIMED_OUT. "
2631 "Attempting to auto-resolve your deadlock. PLEASE FIX!\n", getName(), getRegistryEntryID());
2633 waitToBecomeTerminateThread();
2635 } while (gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
2637 gIOTerminateThread
= NULL
;
2638 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2640 // ! kIOServiceSynchronous
2642 gIOTerminatePhase2List
->setObject( this );
2643 if (0 == gIOTerminateWork
++) {
2644 assert(gIOTerminateWorkerThread
);
2645 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2649 IOLockUnlock( gJobsLock
);
2650 lockForArbitration();
2654 __attribute__((__noreturn__
))
2656 IOService::terminateThread( void * arg
, wait_result_t waitResult
)
2658 // IOLockSleep re-acquires the lock on wakeup, so we only need to do this once
2659 IOLockLock(gJobsLock
);
2661 if (gIOTerminateThread
!= gIOTerminateWorkerThread
) {
2662 waitToBecomeTerminateThread();
2665 while (gIOTerminateWork
) {
2666 terminateWorker((uintptr_t)arg
);
2669 gIOTerminateThread
= NULL
;
2670 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2671 IOLockSleep(gJobsLock
, &gIOTerminateWork
, THREAD_UNINT
);
2676 IOService::scheduleStop( IOService
* provider
)
2678 uint64_t regID1
= getRegistryEntryID();
2679 uint64_t regID2
= provider
->getRegistryEntryID();
2681 TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1
, provider
->getName(), regID2
);
2683 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
2685 (uintptr_t) (regID1
>> 32),
2687 (uintptr_t) (regID2
>> 32));
2689 IOLockLock( gJobsLock
);
2690 gIOStopList
->tailQ( this );
2691 gIOStopProviderList
->tailQ( provider
);
2693 if (0 == gIOTerminateWork
++) {
2694 assert(gIOTerminateWorkerThread
);
2695 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2698 IOLockUnlock( gJobsLock
);
2702 IOService::scheduleFinalize(bool now
)
2704 uint64_t regID1
= getRegistryEntryID();
2706 TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1
);
2708 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
2710 (uintptr_t) (regID1
>> 32),
2713 if (now
|| IOUserClient::finalizeUserReferences(this)) {
2714 IOLockLock( gJobsLock
);
2715 gIOFinalizeList
->tailQ(this);
2716 if (0 == gIOTerminateWork
++) {
2717 assert(gIOTerminateWorkerThread
);
2718 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2720 IOLockUnlock( gJobsLock
);
2725 IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
2727 if (reserved
->uvars
) {
2728 IOUserServer::serviceWillTerminate(this, provider
, options
);
2734 IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
2736 if (reserved
->uvars
) {
2737 IOUserServer::serviceDidTerminate(this, provider
, options
, defer
);
2740 if (false == *defer
) {
2741 if (lockForArbitration( true )) {
2742 if (false == provider
->handleIsOpen( this )) {
2743 scheduleStop( provider
);
2747 message( kIOMessageServiceIsRequestingClose
, provider
, (void *)(uintptr_t) options
);
2748 if (false == provider
->handleIsOpen( this )) {
2749 scheduleStop( provider
);
2753 unlockForArbitration();
2761 IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
2762 OSArray
* doPhase2List
,
2764 void *unused3 __unused
)
2769 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2771 iter
= victim
->getClientIterator();
2773 while ((client
= (IOService
*) iter
->getNextObject())) {
2774 if (user
!= (NULL
!= client
->reserved
->uvars
)) {
2777 regID1
= client
->getRegistryEntryID();
2778 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2779 client
->getName(), regID1
,
2780 victim
->getName(), regID2
, (long long)options
);
2782 IOSERVICE_TERMINATE_WILL
,
2784 (uintptr_t) (regID1
>> 32),
2786 (uintptr_t) (regID2
>> 32));
2788 ok
= client
->willTerminate( victim
, options
);
2789 doPhase2List
->tailQ( client
);
2796 IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2797 void *unused1 __unused
, void *unused2 __unused
,
2798 void *unused3 __unused
)
2803 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2805 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *)(uintptr_t) options
);
2807 iter
= victim
->getClientIterator();
2809 while ((client
= (IOService
*) iter
->getNextObject())) {
2810 regID1
= client
->getRegistryEntryID();
2811 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2812 client
->getName(), regID1
,
2813 victim
->getName(), regID2
, (long long)options
);
2815 client
->didTerminate( victim
, options
, &defer
);
2818 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2819 : IOSERVICE_TERMINATE_DID
),
2821 (uintptr_t) (regID1
>> 32),
2823 (uintptr_t) (regID2
>> 32));
2825 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2826 client
->getName(), regID1
,
2827 victim
->getName(), regID2
, defer
);
2835 IOService::actionWillStop( IOService
* victim
, IOOptionBits options
,
2836 void *unused1 __unused
, void *unused2 __unused
,
2837 void *unused3 __unused
)
2840 IOService
* provider
;
2842 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2844 iter
= victim
->getProviderIterator();
2846 while ((provider
= (IOService
*) iter
->getNextObject())) {
2847 regID1
= provider
->getRegistryEntryID();
2848 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2849 victim
->getName(), regID2
,
2850 provider
->getName(), regID1
, (long long)options
);
2852 IOSERVICE_TERMINATE_WILL
,
2854 (uintptr_t) (regID2
>> 32),
2856 (uintptr_t) (regID1
>> 32));
2858 ok
= victim
->willTerminate( provider
, options
);
2865 IOService::actionDidStop( IOService
* victim
, IOOptionBits options
,
2866 void *unused1 __unused
, void *unused2 __unused
,
2867 void *unused3 __unused
)
2870 IOService
* provider
;
2872 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2874 iter
= victim
->getProviderIterator();
2876 while ((provider
= (IOService
*) iter
->getNextObject())) {
2877 regID1
= provider
->getRegistryEntryID();
2878 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2879 victim
->getName(), regID2
,
2880 provider
->getName(), regID1
, (long long)options
);
2881 victim
->didTerminate( provider
, options
, &defer
);
2884 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2885 : IOSERVICE_TERMINATE_DID
),
2887 (uintptr_t) (regID2
>> 32),
2889 (uintptr_t) (regID1
>> 32));
2891 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2892 victim
->getName(), regID2
,
2893 provider
->getName(), regID1
, defer
);
2901 IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2902 void *unused1 __unused
, void *unused2 __unused
,
2903 void *unused3 __unused
)
2905 uint64_t regID1
= victim
->getRegistryEntryID();
2906 TLOG("%s[0x%qx]::finalize(%08llx)\n", victim
->getName(), regID1
, (long long)options
);
2908 IOSERVICE_TERMINATE_FINALIZE
,
2910 (uintptr_t) (regID1
>> 32),
2913 victim
->finalize( options
);
2917 IOService::actionStop( IOService
* provider
, IOService
* client
,
2918 void *unused1 __unused
, void *unused2 __unused
,
2919 void *unused3 __unused
)
2921 uint64_t regID1
= provider
->getRegistryEntryID();
2922 uint64_t regID2
= client
->getRegistryEntryID();
2924 TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2926 IOSERVICE_TERMINATE_STOP
,
2928 (uintptr_t) (regID1
>> 32),
2930 (uintptr_t) (regID2
>> 32));
2932 client
->stop( provider
);
2933 if (provider
->isOpen( client
)) {
2934 provider
->close( client
);
2937 TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2938 client
->detach( provider
);
2942 IOService::terminateWorker( IOOptionBits options
)
2944 OSArray
* doPhase2List
;
2945 OSArray
* didPhase2List
;
2951 IOService
* provider
;
2957 options
|= kIOServiceRequired
;
2959 doPhase2List
= OSArray::withCapacity( 16 );
2960 didPhase2List
= OSArray::withCapacity( 16 );
2961 freeList
= OSSet::withCapacity( 16 );
2962 if ((NULL
== doPhase2List
) || (NULL
== didPhase2List
) || (NULL
== freeList
)) {
2967 workDone
= gIOTerminateWork
;
2969 while ((victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0))) {
2971 gIOTerminatePhase2List
->removeObject(0);
2972 IOLockUnlock( gJobsLock
);
2974 uint64_t regID1
= victim
->getRegistryEntryID();
2976 IOSERVICE_TERM_START_PHASE2
,
2978 (uintptr_t) (regID1
>> 32),
2983 doPhase2
= victim
->lockForArbitration( true );
2985 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
2987 uint64_t regID1
= victim
->getRegistryEntryID();
2989 IOSERVICE_TERM_TRY_PHASE2
,
2991 (uintptr_t) (regID1
>> 32),
2992 (uintptr_t) victim
->__state
[1],
2995 doPhase2
= (0 == (victim
->__state
[1] &
2996 (kIOServiceTermPhase1State
2997 | kIOServiceTermPhase2State
2998 | kIOServiceConfigState
)));
3000 if (doPhase2
&& (iter
= victim
->getClientIterator())) {
3001 while (doPhase2
&& (client
= (IOService
*) iter
->getNextObject())) {
3002 doPhase2
= (0 == (client
->__state
[1] & kIOServiceStartState
));
3004 uint64_t regID1
= client
->getRegistryEntryID();
3006 IOSERVICE_TERM_UC_DEFER
,
3008 (uintptr_t) (regID1
>> 32),
3009 (uintptr_t) client
->__state
[1],
3011 TLOG("%s[0x%qx]::defer phase2(%s[0x%qx])\n",
3012 victim
->getName(), victim
->getRegistryEntryID(),
3013 client
->getName(), client
->getRegistryEntryID());
3019 victim
->__state
[1] |= kIOServiceTermPhase2State
;
3022 victim
->unlockForArbitration();
3025 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
3026 if (NULL
== victim
->reserved
->uvars
) {
3027 _workLoopAction((IOWorkLoop::Action
) &actionWillStop
,
3028 victim
, (void *)(uintptr_t) options
);
3030 actionWillStop(victim
, options
, NULL
, NULL
, NULL
);
3034 OSArray
* notifiers
;
3035 notifiers
= victim
->copyNotifiers(gIOWillTerminateNotification
, 0, 0xffffffff);
3036 victim
->invokeNotifiers(¬ifiers
);
3038 _workLoopAction((IOWorkLoop::Action
) &actionWillTerminate
,
3040 (void *)(uintptr_t) options
,
3041 (void *)(uintptr_t) doPhase2List
,
3042 (void *)(uintptr_t) false);
3044 actionWillTerminate(
3045 victim
, options
, doPhase2List
, true, NULL
);
3047 didPhase2List
->headQ( victim
);
3050 victim
= (IOService
*) doPhase2List
->getObject(0);
3053 doPhase2List
->removeObject(0);
3057 while ((victim
= (IOService
*) didPhase2List
->getObject(0))) {
3058 bool scheduleFinalize
= false;
3059 if (victim
->lockForArbitration( true )) {
3060 victim
->__state
[1] |= kIOServiceTermPhase3State
;
3061 scheduleFinalize
= (NULL
== victim
->getClient());
3062 victim
->unlockForArbitration();
3064 _workLoopAction((IOWorkLoop::Action
) &actionDidTerminate
,
3065 victim
, (void *)(uintptr_t) options
);
3066 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
3067 _workLoopAction((IOWorkLoop::Action
) &actionDidStop
,
3068 victim
, (void *)(uintptr_t) options
, NULL
);
3070 // no clients - will go to finalize
3071 if (scheduleFinalize
) {
3072 victim
->scheduleFinalize(false);
3074 didPhase2List
->removeObject(0);
3076 IOLockLock( gJobsLock
);
3083 while ((victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
3084 bool sendFinal
= false;
3085 IOLockUnlock( gJobsLock
);
3086 if (victim
->lockForArbitration(true)) {
3087 sendFinal
= (0 == (victim
->__state
[1] & kIOServiceFinalized
));
3089 victim
->__state
[1] |= kIOServiceFinalized
;
3091 victim
->unlockForArbitration();
3094 _workLoopAction((IOWorkLoop::Action
) &actionFinalize
,
3095 victim
, (void *)(uintptr_t) options
);
3097 IOLockLock( gJobsLock
);
3099 freeList
->setObject( victim
);
3100 // safe if finalize list is append only
3101 gIOFinalizeList
->removeObject(0);
3105 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
));) {
3106 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
3109 uint64_t regID1
= provider
->getRegistryEntryID();
3110 uint64_t regID2
= client
->getRegistryEntryID();
3112 if (!provider
->isChild( client
, gIOServicePlane
)) {
3113 // may be multiply queued - nop it
3114 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
3116 IOSERVICE_TERMINATE_STOP_NOP
,
3118 (uintptr_t) (regID1
>> 32),
3120 (uintptr_t) (regID2
>> 32));
3122 // a terminated client is not ready for stop if it has clients, skip it
3123 bool deferStop
= (0 != (kIOServiceInactiveState
& client
->__state
[0]));
3124 IOLockUnlock( gJobsLock
);
3125 if (deferStop
&& client
->lockForArbitration(true)) {
3126 deferStop
= (0 == (client
->__state
[1] & kIOServiceFinalized
));
3127 //deferStop = (!deferStop && (0 != client->getClient()));
3128 //deferStop = (0 != client->getClient());
3129 client
->unlockForArbitration();
3131 TLOG("%s[0x%qx]::defer stop()\n", client
->getName(), regID2
);
3132 IOServiceTrace(IOSERVICE_TERMINATE_STOP_DEFER
,
3134 (uintptr_t) (regID1
>> 32),
3136 (uintptr_t) (regID2
>> 32));
3139 IOLockLock( gJobsLock
);
3143 _workLoopAction((IOWorkLoop::Action
) &actionStop
,
3144 provider
, (void *) client
);
3145 IOLockLock( gJobsLock
);
3146 // check the finalize list now
3150 freeList
->setObject( client
);
3151 freeList
->setObject( provider
);
3153 // safe if stop list is append only
3154 gIOStopList
->removeObject( idx
);
3155 gIOStopProviderList
->removeObject( idx
);
3160 gIOTerminateWork
-= workDone
;
3161 moreToDo
= (gIOTerminateWork
!= 0);
3164 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
3166 IOSERVICE_TERMINATE_DONE
,
3167 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
3171 IOLockUnlock( gJobsLock
);
3173 freeList
->release();
3174 doPhase2List
->release();
3175 didPhase2List
->release();
3177 IOLockLock( gJobsLock
);
3181 IOService::finalize( IOOptionBits options
)
3184 IOService
* provider
;
3185 uint64_t regID1
, regID2
= getRegistryEntryID();
3187 iter
= getProviderIterator();
3191 while ((provider
= (IOService
*) iter
->getNextObject())) {
3193 if (0 == (__state
[1] & kIOServiceTermPhase3State
)) {
3194 /* we come down here on programmatic terminate */
3196 regID1
= provider
->getRegistryEntryID();
3197 TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2
, provider
->getName(), regID1
);
3199 IOSERVICE_TERMINATE_STOP
,
3201 (uintptr_t) (regID1
>> 32),
3203 (uintptr_t) (regID2
>> 32));
3206 if (provider
->isOpen( this )) {
3207 provider
->close( this );
3212 if (provider
->lockForArbitration( true )) {
3213 if (0 == (provider
->__state
[1] & kIOServiceTermPhase3State
)) {
3214 scheduleStop( provider
);
3216 provider
->unlockForArbitration();
3234 IOService::doServiceTerminate( IOOptionBits options
)
3238 // a method in case someone needs to override it
3240 IOService::terminateClient( IOService
* client
, IOOptionBits options
)
3244 if (client
->isParent( this, gIOServicePlane
, true)) {
3245 // we are the clients only provider
3246 ok
= client
->terminate( options
);
3255 IOService::terminate( IOOptionBits options
)
3257 options
|= kIOServiceTerminate
;
3259 return terminatePhase1( options
);
3262 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3268 struct ServiceOpenMessageContext
{
3269 IOService
* service
;
3271 IOService
* excludeClient
;
3272 IOOptionBits options
;
3276 serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
3278 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
3280 if (object
!= context
->excludeClient
) {
3281 context
->service
->messageClient( context
->type
, object
, (void *)(uintptr_t) context
->options
);
3286 IOService::open( IOService
* forClient
,
3287 IOOptionBits options
,
3291 ServiceOpenMessageContext context
;
3293 context
.service
= this;
3294 context
.type
= kIOMessageServiceIsAttemptingOpen
;
3295 context
.excludeClient
= forClient
;
3296 context
.options
= options
;
3298 applyToInterested( gIOGeneralInterest
,
3299 &serviceOpenMessageApplier
, &context
);
3301 if (false == lockForArbitration(false)) {
3305 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
3307 ok
= handleOpen( forClient
, options
, arg
);
3310 if (ok
&& forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3311 forClient
->reserved
->uvars
->userServer
->serviceOpen(this, forClient
);
3314 unlockForArbitration();
3320 IOService::close( IOService
* forClient
,
3321 IOOptionBits options
)
3326 lockForArbitration();
3328 wasClosed
= handleIsOpen( forClient
);
3330 handleClose( forClient
, options
);
3331 last
= (__state
[1] & kIOServiceTermPhase3State
);
3333 if (forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3334 forClient
->reserved
->uvars
->userServer
->serviceClose(this, forClient
);
3338 unlockForArbitration();
3341 forClient
->scheduleStop( this );
3342 } else if (wasClosed
) {
3343 ServiceOpenMessageContext context
;
3345 context
.service
= this;
3346 context
.type
= kIOMessageServiceWasClosed
;
3347 context
.excludeClient
= forClient
;
3348 context
.options
= options
;
3350 applyToInterested( gIOGeneralInterest
,
3351 &serviceOpenMessageApplier
, &context
);
3356 IOService::isOpen( const IOService
* forClient
) const
3358 IOService
* self
= (IOService
*) this;
3361 self
->lockForArbitration();
3363 ok
= handleIsOpen( forClient
);
3365 self
->unlockForArbitration();
3371 IOService::handleOpen( IOService
* forClient
,
3372 IOOptionBits options
,
3377 ok
= (NULL
== __owner
);
3379 __owner
= forClient
;
3380 } else if (options
& kIOServiceSeize
) {
3381 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
3382 __owner
, (void *)(uintptr_t) options
));
3383 if (ok
&& (NULL
== __owner
)) {
3384 __owner
= forClient
;
3393 IOService::handleClose( IOService
* forClient
,
3394 IOOptionBits options
)
3396 if (__owner
== forClient
) {
3402 IOService::handleIsOpen( const IOService
* forClient
) const
3405 return __owner
== forClient
;
3407 return __owner
!= forClient
;
3412 * Probing & starting
3415 IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3417 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
3418 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
3426 val1
= obj1
->priority
;
3430 val2
= obj2
->priority
;
3437 IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
3439 OSDictionary
* dict
;
3440 IOService
* service
;
3441 _IOServiceNotifier
* notify
;
3442 OSSymbol
* key
= (OSSymbol
*) ref
;
3448 result
= kIODefaultProbeScore
;
3449 if ((dict
= OSDynamicCast( OSDictionary
, entry
))) {
3450 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
3451 } else if ((notify
= OSDynamicCast( _IOServiceNotifier
, entry
))) {
3452 return notify
->priority
;
3453 } else if ((service
= OSDynamicCast( IOService
, entry
))) {
3454 prop
= service
->copyProperty(key
);
3455 offset
= OSDynamicCast(OSNumber
, prop
);
3462 result
= offset
->unsigned32BitValue();
3465 OSSafeReleaseNULL(prop
);
3471 IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3473 const OSObject
* obj1
= (const OSObject
*) inObj1
;
3474 const OSObject
* obj2
= (const OSObject
*) inObj2
;
3482 val1
= IOServiceObjectOrder( obj1
, ref
);
3486 val2
= IOServiceObjectOrder( obj2
, ref
);
3493 IOService::copyClientWithCategory( const OSSymbol
* category
)
3495 IOService
* service
= NULL
;
3497 const OSSymbol
* nextCat
;
3499 iter
= getClientIterator();
3501 while ((service
= (IOService
*) iter
->getNextObject())) {
3502 if (kIOServiceInactiveState
& service
->__state
[0]) {
3505 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
3506 service
->getProperty( gIOMatchCategoryKey
));
3507 if (category
== nextCat
) {
3518 IOService::getClientWithCategory( const OSSymbol
* category
)
3521 service
= copyClientWithCategory(category
);
3529 IOService::invokeNotifier( _IOServiceNotifier
* notify
)
3531 _IOServiceNotifierInvocation invocation
;
3534 invocation
.thread
= current_thread();
3536 #if DEBUG_NOTIFIER_LOCKED
3538 if ((count
= isLockedForArbitration(0))) {
3539 IOLog("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3540 panic("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3542 #endif /* DEBUG_NOTIFIER_LOCKED */
3545 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
3548 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
3549 _IOServiceNotifierInvocation
*, link
);
3554 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
3557 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
3558 _IOServiceNotifierInvocation
*, link
);
3559 if (kIOServiceNotifyWaiter
& notify
->state
) {
3560 notify
->state
&= ~kIOServiceNotifyWaiter
;
3561 WAKEUPNOTIFY( notify
);
3570 IOService::invokeNotifiers(OSArray
* willSend
[])
3573 _IOServiceNotifier
* notify
;
3582 for (unsigned int idx
= 0;
3583 (notify
= (_IOServiceNotifier
*) array
->getObject(idx
));
3585 ret
&= invokeNotifier(notify
);
3594 * Alloc and probe matching classes,
3595 * called on the provider instance
3599 IOService::probeCandidates( OSOrderedSet
* matches
)
3601 OSDictionary
* match
= NULL
;
3604 IOService
* newInst
;
3605 OSDictionary
* props
;
3608 OSOrderedSet
* familyMatches
= NULL
;
3609 OSOrderedSet
* startList
;
3610 OSSet
* kexts
= NULL
;
3613 OSDictionary
* startDict
= NULL
;
3614 const OSSymbol
* category
;
3616 _IOServiceNotifier
* notify
;
3617 OSObject
* nextMatch
= NULL
;
3619 bool needReloc
= false;
3620 bool matchDeferred
= false;
3624 IOService
* client
= NULL
;
3627 OSDictionary
* rematchPersonality
;
3632 bool categoryConsumed
;
3636 prop1
= copyProperty(gIORematchPersonalityKey
);
3637 rematchPersonality
= OSDynamicCast(OSDictionary
, prop1
);
3638 if (rematchPersonality
) {
3639 prop2
= copyProperty(gIORematchCountKey
);
3640 num
= OSDynamicCast(OSNumber
, prop2
);
3642 count
= num
->unsigned32BitValue();
3644 OSSafeReleaseNULL(prop2
);
3650 && (nextMatch
= matches
->getFirstObject())) {
3651 nextMatch
->retain();
3652 matches
->removeObject(nextMatch
);
3654 if ((notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
3655 if (0 == (__state
[0] & kIOServiceInactiveState
)) {
3656 invokeNotifier( notify
);
3658 nextMatch
->release();
3661 } else if (!(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
3662 nextMatch
->release();
3669 debugFlags
= getDebugFlags( match
);
3673 isDext
= (NULL
!= match
->getObject(gIOUserServerNameKey
));
3674 if (isDext
&& !(kIODKEnable
& gIODKDebug
)) {
3678 category
= OSDynamicCast( OSSymbol
,
3679 match
->getObject( gIOMatchCategoryKey
));
3680 if (NULL
== category
) {
3681 category
= gIODefaultMatchCategoryKey
;
3683 client
= copyClientWithCategory(category
);
3685 categoryConsumed
= (client
!= NULL
);
3686 if (categoryConsumed
) {
3688 if ((debugFlags
& kIOLogMatch
) && (this != gIOResources
)) {
3689 LOG("%s: match category %s exists\n", getName(),
3690 category
->getCStringNoCopy());
3693 OSSafeReleaseNULL(client
);
3699 // create a copy now in case its modified during matching
3700 props
= OSDictionary::withDictionary(match
, match
->getCount());
3701 if (NULL
== props
) {
3704 props
->setCapacityIncrement(1);
3706 // check the nub matches
3707 if (false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
)) {
3712 if (categoryConsumed
) {
3717 if (rematchPersonality
) {
3718 bool personalityMatch
= match
->isEqualTo(rematchPersonality
);
3719 if (count
> gIODextRelaunchMax
) {
3720 personalityMatch
= !personalityMatch
;
3722 if (!personalityMatch
) {
3727 // Check to see if driver reloc has been loaded.
3728 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
, &kextRef
));
3731 if (debugFlags
& kIOLogCatalogue
) {
3732 LOG("%s: stalling for module\n", getName());
3735 // If reloc hasn't been loaded, exit;
3736 // reprobing will occur after reloc has been loaded.
3740 if (NULL
== kexts
) {
3741 kexts
= OSSet::withCapacity(1);
3744 kexts
->setObject(kextRef
);
3749 // copy saved for rematchng
3750 props
->setObject(gIOMatchedPersonalityKey
, match
);
3752 // reorder on family matchPropertyTable score.
3753 if (NULL
== familyMatches
) {
3754 familyMatches
= OSOrderedSet::withCapacity( 1,
3755 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3757 if (familyMatches
) {
3758 familyMatches
->setObject( props
);
3762 OSSafeReleaseNULL(nextMatch
);
3763 OSSafeReleaseNULL(props
);
3768 if (familyMatches
) {
3770 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
3772 familyMatches
->removeObject( props
);
3777 debugFlags
= getDebugFlags( props
);
3780 symbol
= OSDynamicCast( OSSymbol
,
3781 props
->getObject( gIOClassKey
));
3786 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), IOSERVICE_OBFUSCATE(symbol), IOSERVICE_OBFUSCATE(props));
3788 // alloc the driver instance
3789 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
3791 if (!inst
|| !OSDynamicCast(IOService
, inst
)) {
3792 IOLog("Couldn't alloc class \"%s\"\n",
3793 symbol
->getCStringNoCopy());
3797 // init driver instance
3798 if (!(inst
->init( props
))) {
3800 if (debugFlags
& kIOLogStart
) {
3801 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
3806 if (__state
[1] & kIOServiceSynchronousState
) {
3807 inst
->__state
[1] |= kIOServiceSynchronousState
;
3810 // give the driver the default match category if not specified
3811 category
= OSDynamicCast( OSSymbol
,
3812 props
->getObject( gIOMatchCategoryKey
));
3813 if (NULL
== category
) {
3814 category
= gIODefaultMatchCategoryKey
;
3816 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
3817 // attach driver instance
3818 if (!(inst
->attach( this ))) {
3822 // pass in score from property table
3823 score
= familyMatches
->orderObject( props
);
3825 // & probe the new driver instance
3827 if (debugFlags
& kIOLogProbe
) {
3828 LOG("%s::probe(%s)\n",
3829 inst
->getMetaClass()->getClassName(), getName());
3833 newInst
= inst
->probe( this, &score
);
3834 inst
->detach( this );
3835 if (NULL
== newInst
) {
3837 if (debugFlags
& kIOLogProbe
) {
3838 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
3845 newPri
= OSNumber::withNumber( score
, 32 );
3847 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
3851 // add to start list for the match category
3852 if (NULL
== startDict
) {
3853 startDict
= OSDictionary::withCapacity( 1 );
3855 assert( startDict
);
3856 startList
= (OSOrderedSet
*)
3857 startDict
->getObject( category
);
3858 if (NULL
== startList
) {
3859 startList
= OSOrderedSet::withCapacity( 1,
3860 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3861 if (startDict
&& startList
) {
3862 startDict
->setObject( category
, startList
);
3863 startList
->release();
3866 assert( startList
);
3868 startList
->setObject( newInst
);
3877 familyMatches
->release();
3878 familyMatches
= NULL
;
3881 // start the best (until success) of each category
3883 iter
= OSCollectionIterator::withCollection( startDict
);
3885 while ((category
= (const OSSymbol
*) iter
->getNextObject())) {
3886 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
3887 assert( startList
);
3893 while (true // (!started)
3895 && (inst
= (IOService
*)startList
->getFirstObject())) {
3897 startList
->removeObject(inst
);
3900 debugFlags
= getDebugFlags( inst
);
3902 if (debugFlags
& kIOLogStart
) {
3904 LOG( "match category exists, skipping " );
3906 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
3907 getName(), inst
->getRetainCount());
3910 if (false == started
) {
3912 IOLockLock(gJobsLock
);
3913 matchDeferred
= (gIOMatchDeferList
3914 && (kOSBooleanTrue
== inst
->getProperty(gIOMatchDeferKey
)));
3915 if (matchDeferred
&& (-1U == gIOMatchDeferList
->getNextIndexOfObject(this, 0))) {
3916 gIOMatchDeferList
->setObject(this);
3918 IOLockUnlock(gJobsLock
);
3919 if (matchDeferred
) {
3920 symbol
= OSDynamicCast(OSSymbol
, inst
->getProperty(gIOClassKey
));
3921 IOLog("%s(0x%qx): matching deferred by %s\n",
3922 getName(), getRegistryEntryID(),
3923 symbol
? symbol
->getCStringNoCopy() : "");
3924 // rematching will occur after kextd loads all plists
3927 if (!matchDeferred
) {
3928 started
= startCandidate( inst
);
3930 if ((debugFlags
& kIOLogStart
) && (false == started
)) {
3931 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
3932 inst
->getRetainCount());
3943 OSSafeReleaseNULL(prop1
);
3946 num
= OSNumber::withNumber(dextCount
, 32);
3947 setProperty(gIODEXTMatchCountKey
, num
);
3948 OSSafeReleaseNULL(num
);
3949 } else if (rematchPersonality
) {
3950 removeProperty(gIODEXTMatchCountKey
);
3953 // now that instances are created, drop the refs on any kexts allowing unload
3955 OSKext::dropMatchingReferences(kexts
);
3956 OSSafeReleaseNULL(kexts
);
3959 // adjust the busy count by +1 if matching is stalled for a module,
3960 // or -1 if a previously stalled matching is complete.
3961 lockForArbitration();
3963 uint64_t regID
= getRegistryEntryID();
3966 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
3969 IOSERVICE_MODULESTALL
,
3971 (uintptr_t) (regID
>> 32),
3975 __state
[1] |= kIOServiceModuleStallState
;
3977 } else if (__state
[1] & kIOServiceModuleStallState
) {
3979 IOSERVICE_MODULEUNSTALL
,
3981 (uintptr_t) (regID
>> 32),
3985 __state
[1] &= ~kIOServiceModuleStallState
;
3989 _adjustBusy( adjBusy
);
3991 unlockForArbitration();
3994 startDict
->release();
3999 * Wait for a IOUserServer to check in
4003 __attribute__((noinline
, not_tail_called
))
4005 __WAITING_FOR_USER_SERVER__(OSDictionary
* matching
)
4008 server
= IOService::waitForMatchingService(matching
, kIOUserServerCheckInTimeoutSecs
* NSEC_PER_SEC
);
4013 IOService::willShutdown()
4015 gKextdWillTerminate
= true;
4017 getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
4019 OSKext::willShutdown();
4022 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4025 IOServicePH::init(IOPMrootDomain
* root
)
4027 fUserServers
= OSArray::withCapacity(4);
4028 fMatchingWork
= OSArray::withCapacity(4);
4030 assert(fUserServers
&& fMatchingWork
);
4032 fRootNotifier
= root
->registerInterest(
4033 gIOPriorityPowerStateInterest
, &IOServicePH::systemPowerChange
, NULL
, NULL
);
4035 assert(fRootNotifier
);
4041 IOLockLock(gJobsLock
);
4045 IOServicePH::unlock()
4047 IOLockUnlock(gJobsLock
);
4051 IOServicePH::serverAdd(IOUserServer
* server
)
4056 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4058 fUserServers
->setObject(server
);
4064 IOServicePH::serverRemove(IOUserServer
* server
)
4069 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4071 fUserServers
->removeObject(idx
);
4077 IOServicePH::serverAck(IOUserServer
* server
)
4085 if (server
&& fUserServersWait
) {
4086 idx
= fUserServersWait
->getNextIndexOfObject(server
, 0);
4088 fUserServersWait
->removeObject(idx
);
4089 if (0 == fUserServersWait
->getCount()) {
4090 OSSafeReleaseNULL(fUserServersWait
);
4094 if (!fUserServersWait
&& !fMatchingWork
->getCount()) {
4095 ackTo
= fSystemPowerAckTo
;
4096 ackToRef
= fSystemPowerAckRef
;
4097 fSystemPowerAckTo
= NULL
;
4102 DKLOG("allowPowerChange\n");
4103 ackTo
->allowPowerChange((uintptr_t) ackToRef
);
4108 IOServicePH::matchingStart(IOService
* service
)
4116 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4118 fMatchingWork
->setObject(service
);
4121 if (!fMatchingDelayed
) {
4122 fMatchingDelayed
= OSArray::withObjects((const OSObject
**) &service
, 1, 1);
4124 idx
= fMatchingDelayed
->getNextIndexOfObject(service
, 0);
4126 fMatchingDelayed
->setObject(service
);
4136 IOServicePH::matchingEnd(IOService
* service
)
4139 OSArray
* notifyServers
;
4140 OSArray
* deferredMatches
;
4142 notifyServers
= NULL
;
4143 deferredMatches
= NULL
;
4148 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4150 fMatchingWork
->removeObject(idx
);
4155 if ((fUserServerOff
!= fSystemOff
) && fUserServers
->getCount()) {
4157 if (0 == fMatchingWork
->getCount()) {
4158 fUserServersWait
= OSArray::withArray(fUserServers
);
4159 notifyServers
= OSArray::withArray(fUserServers
);
4160 fUserServerOff
= fSystemOff
;
4163 notifyServers
= OSArray::withArray(fUserServers
);
4164 fUserServerOff
= fSystemOff
;
4168 if (!fSystemOff
&& fMatchingDelayed
) {
4169 deferredMatches
= fMatchingDelayed
;
4170 fMatchingDelayed
= NULL
;
4175 if (notifyServers
) {
4176 notifyServers
->iterateObjects(^bool (OSObject
* obj
) {
4178 us
= (typeof(us
))obj
;
4179 us
->systemPower(fSystemOff
);
4182 OSSafeReleaseNULL(notifyServers
);
4185 if (deferredMatches
) {
4186 DKLOG("sleep deferred rematching count %d\n", deferredMatches
->getCount());
4187 deferredMatches
->iterateObjects(^bool (OSObject
* obj
)
4189 ((IOService
*)obj
)->startMatching(kIOServiceAsynchronous
);
4192 deferredMatches
->release();
4199 IOServicePH::systemPowerChange(
4202 UInt32 messageType
, IOService
* service
,
4203 void * messageArgument
, vm_size_t argSize
)
4207 IOPMSystemCapabilityChangeParameters
* params
;
4211 switch (messageType
) {
4212 case kIOMessageSystemCapabilityChange
:
4214 params
= (typeof params
)messageArgument
;
4216 if (kIODKLogPM
& gIODKDebug
) {
4217 IOLog("IOServicePH::kIOMessageSystemCapabilityChange: %s%s 0x%x->0x%x\n",
4218 params
->changeFlags
& kIOPMSystemCapabilityWillChange
? "will" : "",
4219 params
->changeFlags
& kIOPMSystemCapabilityDidChange
? "did" : "",
4220 params
->fromCapabilities
,
4221 params
->toCapabilities
);
4224 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4225 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
4226 ((params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)) {
4229 fSystemPowerAckRef
= params
->notifyRef
;
4230 fSystemPowerAckTo
= service
;
4235 params
->maxWaitForReply
= 60 * 1000 * 1000;
4236 ret
= kIOReturnSuccess
;
4237 } else if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4238 ((params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0) &&
4239 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
)) {
4246 params
->maxWaitForReply
= 0;
4247 ret
= kIOReturnSuccess
;
4249 params
->maxWaitForReply
= 0;
4250 ret
= kIOReturnSuccess
;
4255 ret
= kIOReturnUnsupported
;
4262 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4265 * Start a previously attached & probed instance,
4266 * called on exporting object instance
4270 IOService::startCandidate( IOService
* service
)
4275 IOUserServer
* userServer
;
4279 obj
= service
->copyProperty(gIOUserServerNameKey
);
4281 if (obj
&& (this == gIOResources
)) {
4284 ok
= service
->attach( this );
4290 if ((this != gIOResources
) && (this != gIOUserResources
)) {
4291 // stall for any nub resources
4293 // stall for any driver resources
4294 service
->checkResources();
4298 OSString
* bundleID
;
4299 OSString
* serverName
;
4301 const OSSymbol
* sym
;
4302 OSDictionary
* matching
;
4304 OSNumber
* serverTag
;
4307 if ((serverName
= OSDynamicCast(OSString
, obj
))) {
4308 obj
= service
->copyProperty(gIOModuleIdentifierKey
);
4309 bundleID
= OSDynamicCast(OSString
, obj
);
4310 entryID
= service
->getRegistryEntryID();
4311 serverTag
= OSNumber::withNumber(entryID
, 64);
4313 if (gKextdWillTerminate
) {
4314 DKLOG("%s disabled in shutdown\n", serverName
->getCStringNoCopy());
4315 service
->detach(this);
4316 OSSafeReleaseNULL(obj
);
4320 ph
= IOServicePH::matchingStart(this);
4322 DKLOG("%s deferred in sleep\n", serverName
->getCStringNoCopy());
4323 service
->detach(this);
4324 OSSafeReleaseNULL(obj
);
4328 prop
= service
->copyProperty(gIOUserClassKey
);
4329 str
= OSDynamicCast(OSString
, prop
);
4331 service
->setName(str
);
4333 OSSafeReleaseNULL(prop
);
4335 if (!(kIODKDisableDextLaunch
& gIODKDebug
)) {
4336 OSKext::requestDaemonLaunch(bundleID
, serverName
, serverTag
);
4338 sym
= OSSymbol::withString(serverName
);
4339 matching
= serviceMatching(gIOUserServerClassKey
);
4340 propertyMatching(gIOUserServerNameKey
, sym
, matching
);
4341 if (!(kIODKDisableDextTag
& gIODKDebug
)) {
4342 propertyMatching(gIOUserServerTagKey
, serverTag
, matching
);
4345 server
= __WAITING_FOR_USER_SERVER__(matching
);
4346 matching
->release();
4347 OSSafeReleaseNULL(serverTag
);
4348 OSSafeReleaseNULL(serverName
);
4350 userServer
= OSDynamicCast(IOUserServer
, server
);
4352 service
->detach(this);
4353 IOServicePH::matchingEnd(this);
4354 DKLOG(DKS
" user server timeout\n", DKN(service
));
4358 if (!(kIODKDisableCDHashChecking
& gIODKDebug
)) {
4359 if (!userServer
->serviceMatchesCDHash(service
)) {
4360 service
->detach(this);
4361 IOServicePH::matchingEnd(this);
4362 userServer
->exit("CDHash check failed");
4363 userServer
->release();
4367 OSKext
*kext
= OSKext::lookupKextWithIdentifier(bundleID
);
4369 const char *name
= bundleID
->getCStringNoCopy();
4370 IOLog("%s Could not find OSKext for %s\n", __func__
, name
);
4377 userServer
->setTaskLoadTag(kext
);
4378 userServer
->setDriverKitUUID(kext
);
4379 OSKext::OSKextLogDriverKitInfoLoad(kext
);
4381 OSSafeReleaseNULL(bundleID
);
4382 OSSafeReleaseNULL(kext
);
4384 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
4385 if (!userServer
->checkEntitlements(this, service
)) {
4386 service
->detach(this);
4387 IOServicePH::matchingEnd(this);
4388 userServer
->exit("Entitlements check failed");
4389 userServer
->release();
4394 userServer
->serviceAttach(service
, this);
4398 AbsoluteTime startTime
;
4399 AbsoluteTime endTime
;
4402 if (kIOLogStart
& gIOKitDebug
) {
4403 clock_get_uptime(&startTime
);
4406 ok
= service
->start(this);
4408 if (kIOLogStart
& gIOKitDebug
) {
4409 clock_get_uptime(&endTime
);
4411 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0) {
4412 SUB_ABSOLUTETIME(&endTime
, &startTime
);
4413 absolutetime_to_nanoseconds(endTime
, &nano
);
4414 if (nano
> 500000000ULL) {
4415 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
4420 userServer
->serviceStarted(service
, this, ok
);
4421 userServer
->release();
4424 service
->detach( this );
4428 IOServicePH::matchingEnd(this);
4435 IOService::publishResource( const char * key
, OSObject
* value
)
4437 const OSSymbol
* sym
;
4439 if ((sym
= OSSymbol::withCString( key
))) {
4440 publishResource( sym
, value
);
4446 IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
4448 if (NULL
== value
) {
4449 value
= (OSObject
*) gIOServiceKey
;
4452 gIOResources
->setProperty( key
, value
);
4454 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4458 gIOResourceGenerationCount
++;
4459 gIOResources
->registerService();
4463 IOService::publishUserResource( const OSSymbol
* key
, OSObject
* value
)
4465 if (NULL
== value
) {
4466 value
= (OSObject
*) gIOServiceKey
;
4469 gIOUserResources
->setProperty( key
, value
);
4471 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4475 gIOResourceGenerationCount
++;
4476 gIOUserResources
->registerService();
4480 IOService::addNeededResource( const char * key
)
4482 OSObject
* resourcesProp
;
4487 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4488 if (!resourcesProp
) {
4492 newKey
= OSString::withCString( key
);
4494 resourcesProp
->release();
4498 set
= OSDynamicCast( OSSet
, resourcesProp
);
4500 set
= OSSet::withCapacity( 1 );
4502 set
->setObject( resourcesProp
);
4508 set
->setObject( newKey
);
4510 ret
= setProperty( gIOResourceMatchKey
, set
);
4512 resourcesProp
->release();
4518 IOService::checkResource( OSObject
* matching
)
4521 OSDictionary
* table
;
4523 if ((str
= OSDynamicCast( OSString
, matching
))) {
4524 if (gIOResources
->getProperty( str
)) {
4530 table
= resourceMatching( str
);
4531 } else if ((table
= OSDynamicCast( OSDictionary
, matching
))) {
4534 IOLog("%s: Can't match using: %s\n", getName(),
4535 matching
->getMetaClass()->getClassName());
4536 /* false would stall forever */
4540 if (gIOKitDebug
& kIOLogConfig
) {
4541 LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName());
4544 waitForService( table
);
4546 if (gIOKitDebug
& kIOLogConfig
) {
4547 LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
4554 IOService::checkResources( void )
4556 OSObject
* resourcesProp
;
4561 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4562 if (NULL
== resourcesProp
) {
4566 if ((set
= OSDynamicCast( OSSet
, resourcesProp
))) {
4567 iter
= OSCollectionIterator::withCollection( set
);
4568 ok
= (NULL
!= iter
);
4569 while (ok
&& (resourcesProp
= iter
->getNextObject())) {
4570 ok
= checkResource( resourcesProp
);
4576 ok
= checkResource( resourcesProp
);
4579 OSSafeReleaseNULL(resourcesProp
);
4586 _IOConfigThread::configThread( int configThreadId
)
4588 _IOConfigThread
* inst
;
4591 if (!(inst
= new _IOConfigThread
)) {
4594 if (!inst
->init()) {
4598 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &thread
)) {
4602 char threadName
[MAXTHREADNAMESIZE
];
4603 snprintf(threadName
, sizeof(threadName
), "IOConfigThread_%d", configThreadId
);
4604 thread_set_thread_name(thread
, threadName
);
4605 thread_deallocate(thread
);
4618 IOService::doServiceMatch( IOOptionBits options
)
4620 _IOServiceNotifier
* notify
;
4622 OSOrderedSet
* matches
;
4623 OSArray
* resourceKeys
= NULL
;
4624 SInt32 catalogGeneration
;
4625 bool keepGuessing
= true;
4626 bool reRegistered
= true;
4628 OSArray
* notifiers
[2] = {NULL
};
4630 // job->nub->deliverNotification( gIOPublishNotification,
4631 // kIOServiceRegisteredState, 0xffffffff );
4633 while (keepGuessing
) {
4634 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
4635 // the matches list should always be created by findDrivers()
4637 lockForArbitration();
4638 if (0 == (__state
[0] & kIOServiceFirstPublishState
)) {
4639 getMetaClass()->addInstance(this);
4640 notifiers
[0] = copyNotifiers(gIOFirstPublishNotification
,
4641 kIOServiceFirstPublishState
, 0xffffffff );
4644 __state
[1] &= ~kIOServiceNeedConfigState
;
4645 __state
[1] |= kIOServiceConfigState
| kIOServiceConfigRunning
;
4646 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
4647 __state
[0] |= kIOServiceRegisteredState
;
4649 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
4650 if (reRegistered
&& keepGuessing
) {
4651 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
4652 gNotifications
->getObject( gIOPublishNotification
));
4654 while ((notify
= (_IOServiceNotifier
*)
4655 iter
->getNextObject())) {
4656 if (matchPassive(notify
->matching
, 0)
4657 && (kIOServiceNotifyEnable
& notify
->state
)) {
4658 matches
->setObject( notify
);
4666 unlockForArbitration();
4667 invokeNotifiers(¬ifiers
[0]);
4669 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources())) {
4670 if ((this == gIOResources
) || (this == gIOUserResources
)) {
4672 resourceKeys
->release();
4674 resourceKeys
= copyPropertyKeys();
4676 probeCandidates( matches
);
4682 lockForArbitration();
4683 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
4685 (reRegistered
|| (catalogGeneration
!=
4686 gIOCatalogue
->getGenerationCount()))
4687 && (0 == (__state
[0] & kIOServiceInactiveState
));
4690 unlockForArbitration();
4694 if ((0 == (__state
[0] & kIOServiceInactiveState
))
4695 && (0 == (__state
[1] & kIOServiceModuleStallState
))) {
4697 setProperty(gIOResourceMatchedKey
, resourceKeys
);
4700 notifiers
[0] = copyNotifiers(gIOMatchedNotification
,
4701 kIOServiceMatchedState
, 0xffffffff);
4702 if (0 == (__state
[0] & kIOServiceFirstMatchState
)) {
4703 notifiers
[1] = copyNotifiers(gIOFirstMatchNotification
,
4704 kIOServiceFirstMatchState
, 0xffffffff);
4708 __state
[1] &= ~kIOServiceConfigRunning
;
4709 unlockForArbitration();
4712 resourceKeys
->release();
4715 invokeNotifiers(¬ifiers
[0]);
4716 invokeNotifiers(¬ifiers
[1]);
4718 lockForArbitration();
4719 __state
[1] &= ~kIOServiceConfigState
;
4720 scheduleTerminatePhase2();
4723 unlockForArbitration();
4727 IOService::_adjustBusy( SInt32 delta
)
4732 bool wasQuiet
, nowQuiet
, needWake
;
4735 result
= __state
[1] & kIOServiceBusyStateMask
;
4740 next
->lockForArbitration();
4742 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
4743 wasQuiet
= (0 == count
);
4744 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
))) {
4745 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
4749 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
4750 nowQuiet
= (0 == count
);
4751 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
4754 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
4755 IOLockLock( gIOServiceBusyLock
);
4756 thread_wakeup((event_t
) next
);
4757 IOLockUnlock( gIOServiceBusyLock
);
4760 next
->unlockForArbitration();
4763 if ((wasQuiet
|| nowQuiet
)) {
4764 uint64_t regID
= next
->getRegistryEntryID();
4766 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
4768 (uintptr_t) (regID
>> 32),
4773 next
->__timeBusy
= mach_absolute_time();
4775 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
4776 next
->__timeBusy
= 0;
4779 MessageClientsContext context
;
4781 context
.service
= next
;
4782 context
.type
= kIOMessageServiceBusyStateChange
;
4783 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
4784 context
.argSize
= 0;
4786 applyToInterestNotifiers( next
, gIOBusyInterest
,
4787 &messageClientsApplier
, &context
);
4790 if (nowQuiet
&& (next
== gIOServiceRoot
)) {
4791 OSKext::considerUnloads();
4792 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
4797 delta
= nowQuiet
? -1 : +1;
4798 } while ((wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
4805 IOService::adjustBusy( SInt32 delta
)
4807 lockForArbitration();
4808 _adjustBusy( delta
);
4809 unlockForArbitration();
4813 IOService::getAccumulatedBusyTime( void )
4815 uint64_t accumBusy
= __accumBusy
;
4816 uint64_t timeBusy
= __timeBusy
;
4820 accumBusy
= __accumBusy
;
4821 timeBusy
= __timeBusy
;
4823 accumBusy
+= mach_absolute_time() - timeBusy
;
4825 }while (timeBusy
!= __timeBusy
);
4827 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
4833 IOService::getBusyState( void )
4835 return __state
[1] & kIOServiceBusyStateMask
;
4839 IOService::waitForState( UInt32 mask
, UInt32 value
,
4840 mach_timespec_t
* timeout
)
4842 panic("waitForState");
4843 return kIOReturnUnsupported
;
4847 IOService::waitForState( UInt32 mask
, UInt32 value
,
4851 int waitResult
= THREAD_AWAKENED
;
4852 bool computeDeadline
= true;
4853 AbsoluteTime abstime
;
4856 lockForArbitration();
4857 IOLockLock( gIOServiceBusyLock
);
4858 wait
= (value
!= (__state
[1] & mask
));
4860 __state
[1] |= kIOServiceBusyWaiterState
;
4861 unlockForArbitration();
4862 if (timeout
!= UINT64_MAX
) {
4863 if (computeDeadline
) {
4864 AbsoluteTime nsinterval
;
4865 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
4866 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
4867 computeDeadline
= false;
4869 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
4871 assert_wait((event_t
)this, THREAD_UNINT
);
4874 unlockForArbitration();
4876 IOLockUnlock( gIOServiceBusyLock
);
4878 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
4880 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
4882 if (waitResult
== THREAD_TIMED_OUT
) {
4883 return kIOReturnTimeout
;
4885 return kIOReturnSuccess
;
4890 IOService::waitQuiet( uint64_t timeout
)
4894 char * string
= NULL
;
4895 char * panicString
= NULL
;
4897 size_t panicStringLen
;
4905 * On kasan kernels, everything takes longer, so double the number of
4906 * timeout extensions. This should help with issues like 41259215
4907 * where WindowServer was timing out waiting for kextd to get all the
4908 * kasan kexts loaded and started.
4910 enum { kTimeoutExtensions
= 8 };
4912 enum { kTimeoutExtensions
= 4 };
4915 time
= mach_absolute_time();
4917 for (loops
= 0; loops
< kTimeoutExtensions
; loops
++) {
4918 ret
= waitForState( kIOServiceBusyStateMask
, 0, timeout
);
4920 if (loops
&& (kIOReturnSuccess
== ret
)) {
4921 time
= mach_absolute_time() - time
;
4922 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&time
, &nano
);
4923 IOLog("busy extended ok[%d], (%llds, %llds)\n",
4924 loops
, timeout
/ 1000000000ULL, nano
/ 1000000000ULL);
4926 } else if (kIOReturnTimeout
!= ret
) {
4928 } else if (timeout
< (4100ull * NSEC_PER_SEC
)) {
4933 IORegistryIterator
* iter
;
4935 OSOrderedSet
* leaves
;
4937 IOService
* nextParent
;
4942 panicStringLen
= 256;
4944 string
= IONew(char, len
);
4947 panicString
= IONew(char, panicStringLen
);
4950 kextdWait
= OSKext::isWaitingKextd();
4951 iter
= IORegistryIterator::iterateOver(this, gIOServicePlane
, kIORegistryIterateRecursively
);
4952 leaves
= OSOrderedSet::withCapacity(4);
4954 set
= iter
->iterateAll();
4956 if (string
&& panicString
&& leaves
&& set
) {
4957 string
[0] = panicString
[0] = 0;
4958 set
->setObject(this);
4959 while ((next
= (IOService
*) set
->getLastObject())) {
4960 if (next
->getBusyState()) {
4961 if (kIOServiceModuleStallState
& next
->__state
[1]) {
4964 leaves
->setObject(next
);
4966 while ((nextParent
= nextParent
->getProvider())) {
4967 set
->removeObject(nextParent
);
4968 leaves
->removeObject(nextParent
);
4971 set
->removeObject(next
);
4974 while ((next
= (IOService
*) leaves
->getLastObject())) {
4975 l
= snprintf(s
, len
, "%s'%s'", ((s
== string
) ? "" : ", "), next
->getName());
4981 leaves
->removeObject(next
);
4984 OSSafeReleaseNULL(leaves
);
4985 OSSafeReleaseNULL(set
);
4986 OSSafeReleaseNULL(iter
);
4989 dopanic
= ((loops
>= (kTimeoutExtensions
- 1)) && (kIOWaitQuietPanics
& gIOKitDebug
));
4990 snprintf(panicString
, panicStringLen
,
4991 "%s[%d], (%llds): %s",
4992 kextdWait
? "kextd stall" : "busy timeout",
4993 loops
, timeout
/ 1000000000ULL,
4994 string
? string
: "");
4995 IOLog("%s\n", panicString
);
4997 panic("%s", panicString
);
4998 } else if (!loops
) {
4999 getPMRootDomain()->startSpinDump(1);
5004 IODelete(string
, char, 256);
5007 IODelete(panicString
, char, panicStringLen
);
5014 IOService::waitQuiet( mach_timespec_t
* timeout
)
5019 timeoutNS
= timeout
->tv_sec
;
5020 timeoutNS
*= kSecondScale
;
5021 timeoutNS
+= timeout
->tv_nsec
;
5023 timeoutNS
= UINT64_MAX
;
5026 return waitQuiet(timeoutNS
);
5030 IOService::serializeProperties( OSSerialize
* s
) const
5033 ((IOService
*)this)->setProperty(((IOService
*)this)->__state
,
5034 sizeof(__state
), "__state");
5036 return super::serializeProperties(s
);
5041 _IOConfigThread::main(void * arg
, wait_result_t result
)
5043 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
5044 _IOServiceJob
* job
;
5048 thread_precedence_policy_data_t precedence
= { -1 };
5050 kr
= thread_policy_set(current_thread(),
5051 THREAD_PRECEDENCE_POLICY
,
5052 (thread_policy_t
) &precedence
,
5053 THREAD_PRECEDENCE_POLICY_COUNT
);
5054 if (KERN_SUCCESS
!= kr
) {
5055 IOLog("thread_policy_set(%d)\n", kr
);
5061 semaphore_wait( gJobsSemaphore
);
5063 IOTakeLock( gJobsLock
);
5064 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
5066 gJobs
->removeObject(job
);
5069 // gNumConfigThreads--; // we're out of service
5070 gNumWaitingThreads
--; // we're out of service
5072 IOUnlock( gJobsLock
);
5077 if (gIOKitDebug
& kIOLogConfig
) {
5078 LOG("config(%p): starting on %s, %d\n",
5079 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->nub
->getName(), job
->type
);
5082 switch (job
->type
) {
5084 nub
->doServiceMatch( job
->options
);
5088 LOG("config(%p): strange type (%d)\n",
5089 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->type
);
5096 IOTakeLock( gJobsLock
);
5097 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
5099 gNumWaitingThreads
++; // back in service
5101 // gNumConfigThreads++;
5103 if (0 == --gNumConfigThreads
) {
5104 // IOLog("MATCH IDLE\n");
5105 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
5108 IOUnlock( gJobsLock
);
5112 if (gIOKitDebug
& kIOLogConfig
) {
5113 LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5120 IOService::waitMatchIdle( UInt32 msToWait
)
5123 int waitResult
= THREAD_AWAKENED
;
5124 bool computeDeadline
= true;
5125 AbsoluteTime deadline
;
5127 IOLockLock( gJobsLock
);
5129 wait
= (0 != gNumConfigThreads
);
5132 if (computeDeadline
) {
5133 clock_interval_to_deadline(
5134 msToWait
, kMillisecondScale
, &deadline
);
5135 computeDeadline
= false;
5137 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
5138 deadline
, THREAD_UNINT
);
5140 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
5144 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
5145 IOLockUnlock( gJobsLock
);
5147 if (waitResult
== THREAD_TIMED_OUT
) {
5148 return kIOReturnTimeout
;
5150 return kIOReturnSuccess
;
5155 IOService::cpusRunning(void)
5157 gCPUsRunning
= true;
5161 _IOServiceJob::pingConfig( _IOServiceJob
* job
)
5168 IOTakeLock( gJobsLock
);
5171 gJobs
->setLastObject( job
);
5173 count
= gNumWaitingThreads
;
5174 // if( gNumConfigThreads) count++;// assume we're called from a config thread
5176 create
= ((gOutstandingJobs
> count
)
5177 && ((gNumConfigThreads
< kMaxConfigThreads
)
5178 || (job
->nub
== gIOResources
)
5181 gNumConfigThreads
++;
5182 gNumWaitingThreads
++;
5185 IOUnlock( gJobsLock
);
5190 if (gIOKitDebug
& kIOLogConfig
) {
5191 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
5193 _IOConfigThread::configThread(gNumConfigThreads
- 1);
5196 semaphore_signal( gJobsSemaphore
);
5199 struct IOServiceMatchContext
{
5200 OSDictionary
* table
;
5209 IOService::instanceMatch(const OSObject
* entry
, void * context
)
5211 IOServiceMatchContext
* ctx
= (typeof(ctx
))context
;
5212 IOService
* service
= (typeof(service
))entry
;
5213 OSDictionary
* table
= ctx
->table
;
5214 uint32_t options
= ctx
->options
;
5215 uint32_t state
= ctx
->state
;
5221 match
= ((state
== (state
& service
->__state
[0]))
5222 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
5226 ctx
->count
+= table
->getCount();
5227 match
= service
->matchInternal(table
, options
, &done
);
5234 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
)) {
5236 ctx
->result
= service
;
5238 } else if (!ctx
->result
) {
5239 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
5241 ((OSSet
*)ctx
->result
)->setObject(service
);
5246 // internal - call with gNotificationLock
5248 IOService::copyExistingServices( OSDictionary
* matching
,
5249 IOOptionBits inState
, IOOptionBits options
)
5251 OSObject
* current
= NULL
;
5253 IOService
* service
;
5262 OSSerialize
* s
= OSSerialize::withCapacity(128);
5263 matching
->serialize(s
);
5266 if ((obj
= matching
->getObject(gIOProviderClassKey
))
5268 && gIOResourcesKey
->isEqualTo(obj
)
5269 && (service
= gIOResources
)) {
5270 if ((inState
== (service
->__state
[0] & inState
))
5271 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5272 && service
->matchPassive(matching
, options
)) {
5273 if (options
& kIONotifyOnce
) {
5277 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
5281 IOServiceMatchContext ctx
;
5282 ctx
.table
= matching
;
5283 ctx
.state
= inState
;
5286 ctx
.options
= options
;
5289 if ((str
= OSDynamicCast(OSString
, obj
))) {
5290 const OSSymbol
* sym
= OSSymbol::withString(str
);
5291 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
5294 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
5298 current
= ctx
.result
;
5300 options
|= kIOServiceInternalDone
| kIOServiceClassDone
;
5301 if (current
&& (ctx
.done
!= ctx
.count
)) {
5303 source
= OSDynamicCast(OSSet
, current
);
5305 while ((service
= (IOService
*) source
->getAnyObject())) {
5306 if (service
->matchPassive(matching
, options
)) {
5307 if (options
& kIONotifyOnce
) {
5313 ((OSSet
*)current
)->setObject( service
);
5315 current
= OSSet::withObjects(
5316 (const OSObject
**) &service
, 1, 1 );
5319 source
->removeObject(service
);
5327 OSObject
* _current
= 0;
5329 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
5330 kIORegistryIterateRecursively
);
5334 while ((service
= (IOService
*) iter
->getNextObject())) {
5335 if ((inState
== (service
->__state
[0] & inState
))
5336 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5337 && service
->matchPassive(matching
, 0)) {
5338 if (options
& kIONotifyOnce
) {
5344 ((OSSet
*)_current
)->setObject( service
);
5346 _current
= OSSet::withObjects(
5347 (const OSObject
**) &service
, 1, 1 );
5351 } while (!service
&& !iter
->isValid());
5355 if (((current
!= 0) != (_current
!= 0))
5356 || (current
&& _current
&& !current
->isEqualTo(_current
))) {
5357 OSSerialize
* s1
= OSSerialize::withCapacity(128);
5358 OSSerialize
* s2
= OSSerialize::withCapacity(128);
5359 current
->serialize(s1
);
5360 _current
->serialize(s2
);
5361 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current
),
5362 IOSERVICE_OBFUSCATE(_current
), s
->text(), s1
->text(), s2
->text());
5368 _current
->release();
5375 if (current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
5376 iter
= OSCollectionIterator::withCollection((OSSet
*)current
);
5386 IOService::getMatchingServices( OSDictionary
* matching
)
5390 // is a lock even needed?
5393 iter
= (OSIterator
*) copyExistingServices( matching
,
5394 kIOServiceMatchedState
);
5402 IOService::copyMatchingService( OSDictionary
* matching
)
5404 IOService
* service
;
5406 // is a lock even needed?
5409 service
= (IOService
*) copyExistingServices( matching
,
5410 kIOServiceMatchedState
, kIONotifyOnce
);
5417 struct _IOServiceMatchingNotificationHandlerRef
{
5418 IOServiceNotificationHandler handler
;
5423 _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
5424 IOService
* newService
,
5425 IONotifier
* notifier
)
5427 return (*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
);
5430 // internal - call with gNotificationLock
5432 IOService::setNotification(
5433 const OSSymbol
* type
, OSDictionary
* matching
,
5434 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
5437 _IOServiceNotifier
* notify
= NULL
;
5444 notify
= new _IOServiceNotifier
;
5445 if (notify
&& !notify
->init()) {
5451 notify
->handler
= handler
;
5452 notify
->target
= target
;
5453 notify
->type
= type
;
5454 notify
->matching
= matching
;
5456 if (handler
== &_IOServiceMatchingNotificationHandler
) {
5457 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
5458 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
5462 notify
->priority
= priority
;
5463 notify
->state
= kIOServiceNotifyEnable
;
5464 queue_init( ¬ify
->handlerInvocations
);
5468 if (NULL
== (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
5469 set
= OSOrderedSet::withCapacity( 1,
5470 IONotifyOrdering
, NULL
);
5472 gNotifications
->setObject( type
, set
);
5476 notify
->whence
= set
;
5478 set
->setObject( notify
);
5485 // internal - call with gNotificationLock
5487 IOService::doInstallNotification(
5488 const OSSymbol
* type
, OSDictionary
* matching
,
5489 IOServiceMatchingNotificationHandler handler
,
5490 void * target
, void * ref
,
5491 SInt32 priority
, OSIterator
** existing
)
5494 IONotifier
* notify
;
5495 IOOptionBits inState
;
5501 if (type
== gIOPublishNotification
) {
5502 inState
= kIOServiceRegisteredState
;
5503 } else if (type
== gIOFirstPublishNotification
) {
5504 inState
= kIOServiceFirstPublishState
;
5505 } else if (type
== gIOMatchedNotification
) {
5506 inState
= kIOServiceMatchedState
;
5507 } else if (type
== gIOFirstMatchNotification
) {
5508 inState
= kIOServiceFirstMatchState
;
5509 } else if ((type
== gIOTerminatedNotification
) || (type
== gIOWillTerminateNotification
)) {
5515 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
5518 // get the current set
5519 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
5529 #if !defined(__LP64__)
5531 IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
5532 IOServiceNotificationHandler handler
,
5533 void * target
, void * refCon
,
5534 SInt32 priority
, OSIterator
** existing
)
5536 IONotifier
* result
;
5537 _IOServiceMatchingNotificationHandlerRef ref
;
5538 ref
.handler
= handler
;
5541 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5542 &_IOServiceMatchingNotificationHandler
,
5543 target
, &ref
, priority
, existing
);
5545 matching
->release();
5550 #endif /* !defined(__LP64__) */
5554 IOService::installNotification(
5555 const OSSymbol
* type
, OSDictionary
* matching
,
5556 IOServiceMatchingNotificationHandler handler
,
5557 void * target
, void * ref
,
5558 SInt32 priority
, OSIterator
** existing
)
5560 IONotifier
* notify
;
5564 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
5565 priority
, existing
);
5567 // in case handler remove()s
5578 IOService::addNotification(
5579 const OSSymbol
* type
, OSDictionary
* matching
,
5580 IOServiceNotificationHandler handler
,
5581 void * target
, void * refCon
,
5584 IONotifier
* result
;
5585 _IOServiceMatchingNotificationHandlerRef ref
;
5587 ref
.handler
= handler
;
5590 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
5591 target
, &ref
, priority
);
5594 matching
->release();
5601 IOService::addMatchingNotification(
5602 const OSSymbol
* type
, OSDictionary
* matching
,
5603 IOServiceMatchingNotificationHandler handler
,
5604 void * target
, void * ref
,
5607 OSIterator
* existing
= NULL
;
5609 _IOServiceNotifier
* notify
;
5612 ret
= notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5613 handler
, target
, ref
, priority
, &existing
);
5618 // send notifications for existing set
5620 while ((next
= (IOService
*) existing
->getNextObject())) {
5621 if (0 == (next
->__state
[0] & kIOServiceInactiveState
)) {
5622 next
->invokeNotifier( notify
);
5625 existing
->release();
5629 bool removed
= (NULL
== notify
->whence
);
5632 ret
= gIOServiceNullNotifier
;
5640 IOServiceMatchingNotificationHandlerToBlock( void * target __unused
, void * refCon
,
5641 IOService
* newService
,
5642 IONotifier
* notifier
)
5644 return ((IOServiceMatchingNotificationHandlerBlock
) refCon
)(newService
, notifier
);
5648 IOService::addMatchingNotification(
5649 const OSSymbol
* type
, OSDictionary
* matching
,
5651 IOServiceMatchingNotificationHandlerBlock handler
)
5653 IONotifier
* notify
;
5656 block
= Block_copy(handler
);
5661 notify
= addMatchingNotification(type
, matching
,
5662 &IOServiceMatchingNotificationHandlerToBlock
, NULL
, block
, priority
);
5665 Block_release(block
);
5673 IOService::syncNotificationHandler(
5674 void * /* target */, void * ref
,
5675 IOService
* newService
,
5676 IONotifier
* notifier
)
5679 if (!*((IOService
**) ref
)) {
5680 newService
->retain();
5681 (*(IOService
**) ref
) = newService
;
5690 IOService::waitForMatchingService( OSDictionary
* matching
,
5693 IONotifier
* notify
= NULL
;
5694 // priority doesn't help us much since we need a thread wakeup
5695 SInt32 priority
= 0;
5706 result
= (IOService
*) copyExistingServices( matching
,
5707 kIOServiceMatchedState
, kIONotifyOnce
);
5711 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
5712 &IOService::syncNotificationHandler
, (void *) NULL
,
5713 &result
, priority
);
5717 if (UINT64_MAX
!= timeout
) {
5718 AbsoluteTime deadline
;
5719 nanoseconds_to_absolutetime(timeout
, &deadline
);
5720 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
5721 SLEEPNOTIFYTO(&result
, deadline
);
5723 SLEEPNOTIFY(&result
);
5730 notify
->remove(); // dequeues
5736 IOService::waitForService( OSDictionary
* matching
,
5737 mach_timespec_t
* timeout
)
5743 timeoutNS
= timeout
->tv_sec
;
5744 timeoutNS
*= kSecondScale
;
5745 timeoutNS
+= timeout
->tv_nsec
;
5747 timeoutNS
= UINT64_MAX
;
5750 result
= waitForMatchingService(matching
, timeoutNS
);
5752 matching
->release();
5762 IOService::deliverNotification( const OSSymbol
* type
,
5763 IOOptionBits orNewState
, IOOptionBits andNewState
)
5765 panic("deliverNotification");
5769 IOService::copyNotifiers(const OSSymbol
* type
,
5770 IOOptionBits orNewState
, IOOptionBits andNewState
)
5772 _IOServiceNotifier
* notify
;
5774 OSArray
* willSend
= NULL
;
5776 lockForArbitration();
5778 if ((0 == (__state
[0] & kIOServiceInactiveState
))
5779 || (type
== gIOTerminatedNotification
)
5780 || (type
== gIOWillTerminateNotification
)) {
5783 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
5784 gNotifications
->getObject( type
));
5787 while ((notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
5788 if (matchPassive(notify
->matching
, 0)
5789 && (kIOServiceNotifyEnable
& notify
->state
)) {
5790 if (NULL
== willSend
) {
5791 willSend
= OSArray::withCapacity(8);
5794 willSend
->setObject( notify
);
5800 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
5804 unlockForArbitration();
5810 IOService::getState( void ) const
5816 * Helpers to make matching objects for simple cases
5820 IOService::serviceMatching( const OSString
* name
,
5821 OSDictionary
* table
)
5823 const OSString
* str
;
5825 str
= OSSymbol::withString(name
);
5831 table
= OSDictionary::withCapacity( 2 );
5834 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
5842 IOService::serviceMatching( const char * name
,
5843 OSDictionary
* table
)
5845 const OSString
* str
;
5847 str
= OSSymbol::withCString( name
);
5852 table
= serviceMatching( str
, table
);
5858 IOService::nameMatching( const OSString
* name
,
5859 OSDictionary
* table
)
5862 table
= OSDictionary::withCapacity( 2 );
5865 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
5872 IOService::nameMatching( const char * name
,
5873 OSDictionary
* table
)
5875 const OSString
* str
;
5877 str
= OSSymbol::withCString( name
);
5882 table
= nameMatching( str
, table
);
5888 IOService::resourceMatching( const OSString
* str
,
5889 OSDictionary
* table
)
5891 table
= serviceMatching( gIOResourcesKey
, table
);
5893 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
5900 IOService::resourceMatching( const char * name
,
5901 OSDictionary
* table
)
5903 const OSSymbol
* str
;
5905 str
= OSSymbol::withCString( name
);
5910 table
= resourceMatching( str
, table
);
5917 IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
5918 OSDictionary
* table
)
5920 OSDictionary
* properties
;
5922 properties
= OSDictionary::withCapacity( 2 );
5926 properties
->setObject( key
, value
);
5929 table
= OSDictionary::withCapacity( 2 );
5932 table
->setObject( gIOPropertyMatchKey
, properties
);
5935 properties
->release();
5941 IOService::registryEntryIDMatching( uint64_t entryID
,
5942 OSDictionary
* table
)
5946 num
= OSNumber::withNumber( entryID
, 64 );
5952 table
= OSDictionary::withCapacity( 2 );
5955 table
->setObject( gIORegistryEntryIDKey
, num
);
5967 * _IOServiceNotifier
5970 // wait for all threads, other than the current one,
5971 // to exit the handler
5974 _IOServiceNotifier::wait()
5976 _IOServiceNotifierInvocation
* next
;
5981 queue_iterate( &handlerInvocations
, next
,
5982 _IOServiceNotifierInvocation
*, link
) {
5983 if (next
->thread
!= current_thread()) {
5989 state
|= kIOServiceNotifyWaiter
;
5996 _IOServiceNotifier::free()
5998 assert( queue_empty( &handlerInvocations
));
6000 if (handler
== &IOServiceMatchingNotificationHandlerToBlock
) {
6008 _IOServiceNotifier::remove()
6013 whence
->removeObject((OSObject
*) this );
6017 matching
->release();
6021 state
&= ~kIOServiceNotifyEnable
;
6031 _IOServiceNotifier::disable()
6037 ret
= (0 != (kIOServiceNotifyEnable
& state
));
6038 state
&= ~kIOServiceNotifyEnable
;
6049 _IOServiceNotifier::enable( bool was
)
6053 state
|= kIOServiceNotifyEnable
;
6055 state
&= ~kIOServiceNotifyEnable
;
6062 * _IOServiceNullNotifier
6066 _IOServiceNullNotifier::taggedRetain(const void *tag
) const
6070 _IOServiceNullNotifier::taggedRelease(const void *tag
, const int when
) const
6074 _IOServiceNullNotifier::free()
6078 _IOServiceNullNotifier::wait()
6082 _IOServiceNullNotifier::remove()
6086 _IOServiceNullNotifier::enable(bool was
)
6090 _IOServiceNullNotifier::disable()
6100 IOResources::resources( void )
6104 inst
= new IOResources
;
6105 if (inst
&& !inst
->init()) {
6114 IOResources::init( OSDictionary
* dictionary
)
6116 // Do super init first
6117 if (!IOService::init()) {
6121 // Allow PAL layer to publish a value
6122 const char *property_name
;
6125 pal_get_resource_property( &property_name
, &property_value
);
6127 if (property_name
) {
6129 const OSSymbol
* sym
;
6131 if ((num
= OSNumber::withNumber(property_value
, 32)) != NULL
) {
6132 if ((sym
= OSSymbol::withCString( property_name
)) != NULL
) {
6133 this->setProperty( sym
, num
);
6144 IOResources::newUserClient(task_t owningTask
, void * securityID
,
6145 UInt32 type
, OSDictionary
* properties
,
6146 IOUserClient
** handler
)
6148 return kIOReturnUnsupported
;
6152 IOResources::getWorkLoop() const
6154 // If we are the resource root
6155 // then use the platform's workloop
6156 if (this == (IOResources
*) gIOResources
) {
6157 return getPlatform()->getWorkLoop();
6159 return IOService::getWorkLoop();
6164 IOResourcesMatchPropertyTable(IOService
* resources
, OSDictionary
* table
)
6174 prop
= table
->getObject( gIOResourceMatchKey
);
6175 str
= OSDynamicCast( OSString
, prop
);
6177 ok
= (NULL
!= resources
->getProperty( str
));
6178 } else if ((set
= OSDynamicCast( OSSet
, prop
))) {
6179 iter
= OSCollectionIterator::withCollection( set
);
6180 ok
= (iter
!= NULL
);
6181 while (ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6182 ok
= (NULL
!= resources
->getProperty( str
));
6188 } else if ((prop
= table
->getObject(gIOResourceMatchedKey
))) {
6189 obj
= resources
->copyProperty(gIOResourceMatchedKey
);
6190 keys
= OSDynamicCast(OSArray
, obj
);
6193 // assuming OSSymbol
6194 ok
= ((-1U) != keys
->getNextIndexOfObject(prop
, 0));
6196 OSSafeReleaseNULL(obj
);
6203 IOResources::matchPropertyTable( OSDictionary
* table
)
6205 return IOResourcesMatchPropertyTable(this, table
);
6213 IOUserResources::resources( void )
6215 IOUserResources
* inst
;
6217 inst
= OSTypeAlloc(IOUserResources
);
6218 if (inst
&& !inst
->init()) {
6227 IOUserResources::init( OSDictionary
* dictionary
)
6229 // Do super init first
6230 if (!IOService::init()) {
6237 IOUserResources::newUserClient(task_t owningTask
, void * securityID
,
6238 UInt32 type
, OSDictionary
* properties
,
6239 IOUserClient
** handler
)
6241 return kIOReturnUnsupported
;
6245 IOUserResources::getWorkLoop() const
6247 return getPlatform()->getWorkLoop();
6251 IOUserResources::matchPropertyTable( OSDictionary
* table
)
6253 return IOResourcesMatchPropertyTable(this, table
);
6259 IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
6261 IOService::updateConsoleUsers(NULL
, 0);
6265 IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
)
6267 IORegistryEntry
* regEntry
;
6268 OSObject
* locked
= kOSBooleanFalse
;
6271 OSDictionary
* user
;
6272 static IOMessage sSystemPower
;
6273 clock_sec_t now
= 0;
6274 clock_usec_t microsecs
;
6276 regEntry
= IORegistryEntry::getRegistryRoot();
6278 if (!gIOChosenEntry
) {
6279 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
6282 IOLockLock(gIOConsoleUsersLock
);
6284 if (systemMessage
) {
6285 sSystemPower
= systemMessage
;
6287 if (kIOMessageSystemHasPoweredOn
== systemMessage
) {
6288 uint32_t lockState
= IOHibernateWasScreenLocked();
6289 switch (lockState
) {
6292 case kIOScreenLockLocked
:
6293 case kIOScreenLockFileVaultDialog
:
6294 gIOConsoleBooterLockState
= kOSBooleanTrue
;
6296 case kIOScreenLockNoLock
:
6297 gIOConsoleBooterLockState
= NULL
;
6299 case kIOScreenLockUnlocked
:
6301 gIOConsoleBooterLockState
= kOSBooleanFalse
;
6305 #endif /* HIBERNATION */
6309 OSNumber
* num
= NULL
;
6310 bool loginLocked
= true;
6312 gIOConsoleLoggedIn
= false;
6314 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
6316 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
6317 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
6319 loginLocked
&= (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionScreenIsLockedKey
));
6321 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
6326 gIOConsoleBooterLockState
= NULL
;
6328 IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
6329 (num
!= NULL
), gIOConsoleLockTime
, (num
? num
->unsigned32BitValue() : 0),
6330 gIOConsoleLoggedIn
, loginLocked
);
6331 #endif /* HIBERNATION */
6332 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
6335 if (!gIOConsoleLoggedIn
6336 || (kIOMessageSystemWillSleep
== sSystemPower
)
6337 || (kIOMessageSystemPagingOff
== sSystemPower
)) {
6338 locked
= kOSBooleanTrue
;
6341 else if (gIOConsoleBooterLockState
) {
6342 locked
= gIOConsoleBooterLockState
;
6344 #endif /* HIBERNATION */
6345 else if (gIOConsoleLockTime
) {
6346 clock_get_calendar_microtime(&now
, µsecs
);
6347 if (gIOConsoleLockTime
> now
) {
6348 AbsoluteTime deadline
;
6349 clock_interval_to_deadline(gIOConsoleLockTime
- now
, kSecondScale
, &deadline
);
6350 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
6352 locked
= kOSBooleanTrue
;
6356 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
6358 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
6360 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
6362 OSIncrementAtomic( &gIOConsoleUsersSeed
);
6366 if (gIOChosenEntry
) {
6367 if (locked
== kOSBooleanTrue
) {
6368 gIOScreenLockState
= kIOScreenLockLocked
;
6369 } else if (gIOConsoleLockTime
) {
6370 gIOScreenLockState
= kIOScreenLockUnlocked
;
6372 gIOScreenLockState
= kIOScreenLockNoLock
;
6374 gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &gIOScreenLockState
, sizeof(gIOScreenLockState
));
6376 IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
6377 gIOScreenLockState
, gIOHibernateState
, (gIOConsoleBooterLockState
!= NULL
), now
, systemMessage
);
6379 #endif /* HIBERNATION */
6381 IOLockUnlock(gIOConsoleUsersLock
);
6384 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
6386 MessageClientsContext context
;
6388 context
.service
= getServiceRoot();
6389 context
.type
= kIOMessageConsoleSecurityChange
;
6390 context
.argument
= (void *) regEntry
;
6391 context
.argSize
= 0;
6393 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
6394 &messageClientsApplier
, &context
);
6399 IOResources::setProperties( OSObject
* properties
)
6402 const OSSymbol
* key
;
6403 OSDictionary
* dict
;
6404 OSCollectionIterator
* iter
;
6406 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
6407 if (kIOReturnSuccess
!= err
) {
6411 dict
= OSDynamicCast(OSDictionary
, properties
);
6413 return kIOReturnBadArgument
;
6416 iter
= OSCollectionIterator::withCollection( dict
);
6418 return kIOReturnBadArgument
;
6421 while ((key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
6422 if (gIOConsoleUsersKey
== key
) {
6424 OSArray
* consoleUsers
;
6425 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
6426 if (!consoleUsers
) {
6429 IOService::updateConsoleUsers(consoleUsers
, 0);
6433 publishResource( key
, dict
->getObject(key
));
6438 return kIOReturnSuccess
;
6442 * Helpers for matching dictionaries.
6443 * Keys existing in matching are checked in properties.
6444 * Keys may be a string or OSCollection of IOStrings
6448 IOService::compareProperty( OSDictionary
* matching
,
6455 value
= matching
->getObject( key
);
6457 prop
= copyProperty(key
);
6458 ok
= value
->isEqualTo(prop
);
6471 IOService::compareProperty( OSDictionary
* matching
,
6472 const OSString
* key
)
6478 value
= matching
->getObject( key
);
6480 prop
= copyProperty(key
);
6481 ok
= value
->isEqualTo(prop
);
6493 IOService::compareProperties( OSDictionary
* matching
,
6494 OSCollection
* keys
)
6496 OSCollectionIterator
* iter
;
6497 const OSString
* key
;
6500 if (!matching
|| !keys
) {
6504 iter
= OSCollectionIterator::withCollection( keys
);
6507 while (ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6508 ok
= compareProperty( matching
, key
);
6513 keys
->release(); // !! consume a ref !!
6518 /* Helper to add a location matching dict to the table */
6521 IOService::addLocation( OSDictionary
* table
)
6523 OSDictionary
* dict
;
6529 dict
= OSDictionary::withCapacity( 1 );
6531 bool ok
= table
->setObject( gIOLocationMatchKey
, dict
);
6542 * Go looking for a provider to match a location dict.
6546 IOService::matchLocation( IOService
* /* client */ )
6550 parent
= getProvider();
6553 parent
= parent
->matchLocation( this );
6560 IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
6565 IORegistryEntry
* entry
;
6568 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
6573 count
= table
->getCount();
6576 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
6579 match
= ((kIOServiceClassDone
& options
) || (NULL
!= metaCast(str
)));
6581 match
= (0 != metaCast( str
));
6582 if ((kIOServiceClassDone
& options
) && !match
) {
6586 if ((!match
) || (done
== count
)) {
6591 obj
= table
->getObject( gIONameMatchKey
);
6594 match
= compareNames( obj
, changesOK
? &matched
: NULL
);
6598 if (changesOK
&& matched
) {
6599 // leave a hint as to which name matched
6600 table
->setObject( gIONameMatchedKey
, matched
);
6603 if (done
== count
) {
6608 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
6610 const OSSymbol
* sym
;
6613 sym
= copyLocation();
6615 match
= sym
->isEqualTo( str
);
6618 if ((!match
) || (done
== count
)) {
6623 obj
= table
->getObject( gIOPropertyMatchKey
);
6625 OSDictionary
* dict
;
6626 OSDictionary
* nextDict
;
6630 dict
= dictionaryWithProperties();
6632 nextDict
= OSDynamicCast( OSDictionary
, obj
);
6636 iter
= OSCollectionIterator::withCollection(
6637 OSDynamicCast(OSCollection
, obj
));
6641 || (iter
&& (NULL
!= (nextDict
= OSDynamicCast(OSDictionary
,
6642 iter
->getNextObject()))))) {
6643 match
= dict
->isEqualTo( nextDict
, nextDict
);
6654 if ((!match
) || (done
== count
)) {
6659 obj
= table
->getObject( gIOPropertyExistsMatchKey
);
6661 OSDictionary
* dict
;
6666 dict
= dictionaryWithProperties();
6668 nextKey
= OSDynamicCast( OSString
, obj
);
6672 iter
= OSCollectionIterator::withCollection(
6673 OSDynamicCast(OSCollection
, obj
));
6677 || (iter
&& (NULL
!= (nextKey
= OSDynamicCast(OSString
,
6678 iter
->getNextObject()))))) {
6679 match
= (NULL
!= dict
->getObject(nextKey
));
6690 if ((!match
) || (done
== count
)) {
6695 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
6698 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy());
6699 match
= (this == entry
);
6703 if ((!match
) || (done
== count
)) {
6708 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
6711 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
6712 if ((!match
) || (done
== count
)) {
6717 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
6720 IOService
* service
= NULL
;
6721 UInt32 serviceCount
= 0;
6724 iter
= getClientIterator();
6726 while ((service
= (IOService
*) iter
->getNextObject())) {
6727 if (kIOServiceInactiveState
& service
->__state
[0]) {
6730 if (NULL
== service
->getProperty( gIOMatchCategoryKey
)) {
6737 match
= (serviceCount
== num
->unsigned32BitValue());
6738 if ((!match
) || (done
== count
)) {
6743 #define propMatch(key) \
6744 obj = table->getObject(key); \
6749 prop = copyProperty(key); \
6750 match = obj->isEqualTo(prop); \
6751 if (prop) prop->release(); \
6752 if ((!match) || (done == count)) break; \
6754 propMatch(gIOBSDNameKey
)
6755 propMatch(gIOBSDMajorKey
)
6756 propMatch(gIOBSDMinorKey
)
6757 propMatch(gIOBSDUnitKey
)
6768 IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
6770 return matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0);
6774 IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
6777 OSDictionary
* nextTable
;
6781 bool matchParent
= false;
6787 #if !CONFIG_EMBEDDED
6788 OSArray
* aliasServiceRegIds
= NULL
;
6789 IOService
* foundAlternateService
= NULL
;
6793 OSDictionary
* root
= table
;
6799 count
= table
->getCount();
6800 if (!(kIOServiceInternalDone
& options
)) {
6801 match
= where
->matchInternal(table
, options
, &done
);
6802 // don't call family if we've done all the entries in the table
6803 if ((!match
) || (done
== count
)) {
6808 // pass in score from property table
6809 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
6811 // do family specific matching
6812 match
= where
->matchPropertyTable( table
, &score
);
6816 if (kIOLogMatch
& getDebugFlags( table
)) {
6817 LOG("%s: family specific matching fails\n", where
->getName());
6823 if (kIOServiceChangesOK
& options
) {
6825 newPri
= OSNumber::withNumber( score
, 32 );
6827 table
->setObject( gIOProbeScoreKey
, newPri
);
6833 matchParent
= false;
6835 nextTable
= OSDynamicCast(OSDictionary
,
6836 table
->getObject( gIOParentMatchKey
));
6838 // look for a matching entry anywhere up to root
6845 table
= OSDynamicCast(OSDictionary
,
6846 table
->getObject( gIOLocationMatchKey
));
6848 // look for a matching entry at matchLocation()
6850 where
= where
->getProvider();
6851 if (where
&& (where
= where
->matchLocation(where
))) {
6858 if (match
== true) {
6862 if (matchParent
== true) {
6863 #if !CONFIG_EMBEDDED
6864 // check if service has an alias to search its other "parents" if a parent match isn't found
6865 OSObject
* prop
= where
->copyProperty(gIOServiceLegacyMatchingRegistryIDKey
);
6866 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, prop
);
6867 if (alternateRegistryID
!= NULL
) {
6868 if (aliasServiceRegIds
== NULL
) {
6869 aliasServiceRegIds
= OSArray::withCapacity(sizeof(alternateRegistryID
));
6871 aliasServiceRegIds
->setObject(alternateRegistryID
);
6873 OSSafeReleaseNULL(prop
);
6879 where
= where
->getProvider();
6880 #if !CONFIG_EMBEDDED
6881 if (where
== NULL
) {
6882 // there were no matching parent services, check to see if there are aliased services that have a matching parent
6883 if (aliasServiceRegIds
!= NULL
) {
6884 unsigned int numAliasedServices
= aliasServiceRegIds
->getCount();
6885 if (numAliasedServices
!= 0) {
6886 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, aliasServiceRegIds
->getObject(numAliasedServices
- 1));
6887 if (alternateRegistryID
!= NULL
) {
6888 OSDictionary
* alternateMatchingDict
= IOService::registryEntryIDMatching(alternateRegistryID
->unsigned64BitValue());
6889 aliasServiceRegIds
->removeObject(numAliasedServices
- 1);
6890 if (alternateMatchingDict
!= NULL
) {
6891 OSSafeReleaseNULL(foundAlternateService
);
6892 foundAlternateService
= IOService::copyMatchingService(alternateMatchingDict
);
6893 alternateMatchingDict
->release();
6894 if (foundAlternateService
!= NULL
) {
6895 where
= foundAlternateService
;
6903 }while (where
!= NULL
);
6905 #if !CONFIG_EMBEDDED
6906 OSSafeReleaseNULL(foundAlternateService
);
6907 OSSafeReleaseNULL(aliasServiceRegIds
);
6911 if (where
!= this) {
6912 OSSerialize
* s
= OSSerialize::withCapacity(128);
6914 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
6924 IOService::newUserClient( task_t owningTask
, void * securityID
,
6925 UInt32 type
, OSDictionary
* properties
,
6926 IOUserClient
** handler
)
6928 const OSSymbol
*userClientClass
= NULL
;
6929 IOUserClient
*client
;
6933 if (reserved
&& reserved
->uvars
&& reserved
->uvars
->userServer
) {
6934 return reserved
->uvars
->userServer
->serviceNewUserClient(this, owningTask
, securityID
, type
, properties
, handler
);
6937 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
)) {
6938 return kIOReturnSuccess
;
6941 // First try my own properties for a user client class name
6942 prop
= copyProperty(gIOUserClientClassKey
);
6944 if (OSDynamicCast(OSSymbol
, prop
)) {
6945 userClientClass
= (const OSSymbol
*) prop
;
6946 } else if (OSDynamicCast(OSString
, prop
)) {
6947 userClientClass
= OSSymbol::withString((OSString
*) prop
);
6948 if (userClientClass
) {
6949 setProperty(gIOUserClientClassKey
,
6950 (OSObject
*) userClientClass
);
6955 // Didn't find one so lets just bomb out now without further ado.
6956 if (!userClientClass
) {
6957 OSSafeReleaseNULL(prop
);
6958 return kIOReturnUnsupported
;
6961 // This reference is consumed by the IOServiceOpen call
6962 temp
= OSMetaClass::allocClassWithName(userClientClass
);
6963 OSSafeReleaseNULL(prop
);
6965 return kIOReturnNoMemory
;
6968 if (OSDynamicCast(IOUserClient
, temp
)) {
6969 client
= (IOUserClient
*) temp
;
6972 return kIOReturnUnsupported
;
6975 if (!client
->initWithTask(owningTask
, securityID
, type
, properties
)) {
6977 return kIOReturnBadArgument
;
6980 if (!client
->attach(this)) {
6982 return kIOReturnUnsupported
;
6985 if (!client
->start(this)) {
6986 client
->detach(this);
6988 return kIOReturnUnsupported
;
6992 return kIOReturnSuccess
;
6996 IOService::newUserClient( task_t owningTask
, void * securityID
,
6997 UInt32 type
, IOUserClient
** handler
)
6999 return kIOReturnUnsupported
;
7003 IOService::requestProbe( IOOptionBits options
)
7005 return kIOReturnUnsupported
;
7009 * Convert an IOReturn to text. Subclasses which add additional
7010 * IOReturn's should override this method and call
7011 * super::stringFromReturn if the desired value is not found.
7015 IOService::stringFromReturn( IOReturn rtn
)
7017 static const IONamedValue IOReturn_values
[] = {
7018 {kIOReturnSuccess
, "success" },
7019 {kIOReturnError
, "general error" },
7020 {kIOReturnNoMemory
, "memory allocation error" },
7021 {kIOReturnNoResources
, "resource shortage" },
7022 {kIOReturnIPCError
, "Mach IPC failure" },
7023 {kIOReturnNoDevice
, "no such device" },
7024 {kIOReturnNotPrivileged
, "privilege violation" },
7025 {kIOReturnBadArgument
, "invalid argument" },
7026 {kIOReturnLockedRead
, "device is read locked" },
7027 {kIOReturnLockedWrite
, "device is write locked" },
7028 {kIOReturnExclusiveAccess
, "device is exclusive access" },
7029 {kIOReturnBadMessageID
, "bad IPC message ID" },
7030 {kIOReturnUnsupported
, "unsupported function" },
7031 {kIOReturnVMError
, "virtual memory error" },
7032 {kIOReturnInternalError
, "internal driver error" },
7033 {kIOReturnIOError
, "I/O error" },
7034 {kIOReturnCannotLock
, "cannot acquire lock" },
7035 {kIOReturnNotOpen
, "device is not open" },
7036 {kIOReturnNotReadable
, "device is not readable" },
7037 {kIOReturnNotWritable
, "device is not writeable" },
7038 {kIOReturnNotAligned
, "alignment error" },
7039 {kIOReturnBadMedia
, "media error" },
7040 {kIOReturnStillOpen
, "device is still open" },
7041 {kIOReturnRLDError
, "rld failure" },
7042 {kIOReturnDMAError
, "DMA failure" },
7043 {kIOReturnBusy
, "device is busy" },
7044 {kIOReturnTimeout
, "I/O timeout" },
7045 {kIOReturnOffline
, "device is offline" },
7046 {kIOReturnNotReady
, "device is not ready" },
7047 {kIOReturnNotAttached
, "device/channel is not attached" },
7048 {kIOReturnNoChannels
, "no DMA channels available" },
7049 {kIOReturnNoSpace
, "no space for data" },
7050 {kIOReturnPortExists
, "device port already exists" },
7051 {kIOReturnCannotWire
, "cannot wire physical memory" },
7052 {kIOReturnNoInterrupt
, "no interrupt attached" },
7053 {kIOReturnNoFrames
, "no DMA frames enqueued" },
7054 {kIOReturnMessageTooLarge
, "message is too large" },
7055 {kIOReturnNotPermitted
, "operation is not permitted" },
7056 {kIOReturnNoPower
, "device is without power" },
7057 {kIOReturnNoMedia
, "media is not present" },
7058 {kIOReturnUnformattedMedia
, "media is not formatted" },
7059 {kIOReturnUnsupportedMode
, "unsupported mode" },
7060 {kIOReturnUnderrun
, "data underrun" },
7061 {kIOReturnOverrun
, "data overrun" },
7062 {kIOReturnDeviceError
, "device error" },
7063 {kIOReturnNoCompletion
, "no completion routine" },
7064 {kIOReturnAborted
, "operation was aborted" },
7065 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
7066 {kIOReturnNotResponding
, "device is not responding" },
7067 {kIOReturnInvalid
, "unanticipated driver error" },
7071 return IOFindNameForValue(rtn
, IOReturn_values
);
7075 * Convert an IOReturn to an errno.
7078 IOService::errnoFromReturn( IOReturn rtn
)
7080 if (unix_err(err_get_code(rtn
)) == rtn
) {
7081 return err_get_code(rtn
);
7086 case kIOReturnSuccess
:
7088 case kIOReturnNoMemory
:
7090 case kIOReturnNoDevice
:
7092 case kIOReturnVMError
:
7094 case kIOReturnNotPermitted
:
7096 case kIOReturnNotPrivileged
:
7098 case kIOReturnIOError
:
7100 case kIOReturnNotWritable
:
7102 case kIOReturnBadArgument
:
7104 case kIOReturnUnsupported
:
7108 case kIOReturnNoPower
:
7110 case kIOReturnDeviceError
:
7112 case kIOReturnTimeout
:
7114 case kIOReturnMessageTooLarge
:
7116 case kIOReturnNoSpace
:
7118 case kIOReturnCannotLock
:
7122 case kIOReturnBadMessageID
:
7123 case kIOReturnNoCompletion
:
7124 case kIOReturnNotAligned
:
7126 case kIOReturnNotReady
:
7128 case kIOReturnRLDError
:
7130 case kIOReturnPortExists
:
7131 case kIOReturnStillOpen
:
7133 case kIOReturnExclusiveAccess
:
7134 case kIOReturnLockedRead
:
7135 case kIOReturnLockedWrite
:
7136 case kIOReturnNotOpen
:
7137 case kIOReturnNotReadable
:
7139 case kIOReturnCannotWire
:
7140 case kIOReturnNoResources
:
7142 case kIOReturnAborted
:
7143 case kIOReturnOffline
:
7144 case kIOReturnNotResponding
:
7146 case kIOReturnBadMedia
:
7147 case kIOReturnNoMedia
:
7148 case kIOReturnNotAttached
:
7149 case kIOReturnUnformattedMedia
:
7150 return ENXIO
; // (media error)
7151 case kIOReturnDMAError
:
7152 case kIOReturnOverrun
:
7153 case kIOReturnUnderrun
:
7154 return EIO
; // (transfer error)
7155 case kIOReturnNoBandwidth
:
7156 case kIOReturnNoChannels
:
7157 case kIOReturnNoFrames
:
7158 case kIOReturnNoInterrupt
:
7159 return EIO
; // (hardware error)
7160 case kIOReturnError
:
7161 case kIOReturnInternalError
:
7162 case kIOReturnInvalid
:
7163 return EIO
; // (generic error)
7164 case kIOReturnIPCError
:
7165 return EIO
; // (ipc error)
7167 return EIO
; // (all other errors)
7172 IOService::message( UInt32 type
, IOService
* provider
,
7176 * Generic entry point for calls from the provider. A return value of
7177 * kIOReturnSuccess indicates that the message was received, and where
7178 * applicable, that it was successful.
7181 return kIOReturnUnsupported
;
7189 IOService::getDeviceMemoryCount( void )
7194 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7196 count
= array
->getCount();
7205 IOService::getDeviceMemoryWithIndex( unsigned int index
)
7208 IODeviceMemory
* range
;
7210 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7212 range
= (IODeviceMemory
*) array
->getObject( index
);
7221 IOService::mapDeviceMemoryWithIndex( unsigned int index
,
7222 IOOptionBits options
)
7224 IODeviceMemory
* range
;
7227 range
= getDeviceMemoryWithIndex( index
);
7229 map
= range
->map( options
);
7238 IOService::getDeviceMemory( void )
7240 return OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7245 IOService::setDeviceMemory( OSArray
* array
)
7247 setProperty( gIODeviceMemoryKey
, array
);
7251 * For machines where the transfers on an I/O bus can stall because
7252 * the CPU is in an idle mode, These APIs allow a driver to specify
7253 * the maximum bus stall that they can handle. 0 indicates no limit.
7257 setCPUSnoopDelay(UInt32 __unused ns
)
7259 #if defined(__i386__) || defined(__x86_64__)
7260 ml_set_maxsnoop(ns
);
7261 #endif /* defined(__i386__) || defined(__x86_64__) */
7268 #if defined(__i386__) || defined(__x86_64__)
7269 return ml_get_maxsnoop();
7272 #endif /* defined(__i386__) || defined(__x86_64__) */
7275 #if defined(__i386__) || defined(__x86_64__)
7277 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
7279 static const UInt kNoReplace
= -1U; // Must be an illegal index
7280 UInt replace
= kNoReplace
;
7281 bool setCpuDelay
= false;
7283 IORecursiveLockLock(sCpuDelayLock
);
7285 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7286 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7287 IOService
* holder
= NULL
;
7290 const CpuDelayEntry ne
= {service
, ns
, delayType
};
7292 // Set maximum delay.
7293 for (UInt i
= 0; i
< count
; i
++) {
7294 IOService
*thisService
= entries
[i
].fService
;
7295 bool sameType
= (delayType
== entries
[i
].fDelayType
);
7296 if ((service
== thisService
) && sameType
) {
7298 } else if (!thisService
) {
7299 if (kNoReplace
== replace
) {
7302 } else if (sameType
) {
7303 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
7306 holder
= thisService
;
7312 if (kNoReplace
== replace
) {
7313 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
7315 entries
[replace
] = ne
;
7318 ns
= -1U; // Set to max unsigned, i.e. no restriction
7320 for (UInt i
= 0; i
< count
; i
++) {
7321 // Clear a maximum delay.
7322 IOService
*thisService
= entries
[i
].fService
;
7323 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
7324 UInt32 thisMax
= entries
[i
].fMaxDelay
;
7325 if (service
== thisService
) {
7327 } else if (thisMax
< ns
) {
7329 holder
= thisService
;
7334 // Check if entry found
7335 if (kNoReplace
!= replace
) {
7336 entries
[replace
].fService
= NULL
; // Null the entry
7342 if (holder
&& debug_boot_arg
) {
7343 strlcpy(sCPULatencyHolderName
[delayType
], holder
->getName(), sizeof(sCPULatencyHolderName
[delayType
]));
7346 // Must be safe to call from locked context
7347 if (delayType
== kCpuDelayBusStall
) {
7348 ml_set_maxbusdelay(ns
);
7349 } else if (delayType
== kCpuDelayInterrupt
) {
7350 ml_set_maxintdelay(ns
);
7352 sCPULatencyHolder
[delayType
]->setValue(holder
? holder
->getRegistryEntryID() : 0);
7353 sCPULatencySet
[delayType
]->setValue(ns
);
7355 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
7358 for (unsigned int idx
= 0;
7359 (target
= (IOService
*) handlers
->getObject(idx
));
7361 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7362 (void *) (uintptr_t) ns
, holder
,
7368 IORecursiveLockUnlock(sCpuDelayLock
);
7372 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
7374 IOReturn result
= kIOReturnNotFound
;
7378 IORecursiveLockLock(sCpuDelayLock
);
7381 if (enable
&& !sCpuLatencyHandlers
[delayType
]) {
7382 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
7384 array
= sCpuLatencyHandlers
[delayType
];
7388 idx
= array
->getNextIndexOfObject(target
, 0);
7391 array
->removeObject(idx
);
7392 result
= kIOReturnSuccess
;
7396 result
= kIOReturnExclusiveAccess
;
7399 array
->setObject(target
);
7401 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7402 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7403 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
7404 IOService
* holder
= NULL
;
7406 for (UInt i
= 0; i
< count
; i
++) {
7407 if (entries
[i
].fService
7408 && (delayType
== entries
[i
].fDelayType
)
7409 && (entries
[i
].fMaxDelay
< ns
)) {
7410 ns
= entries
[i
].fMaxDelay
;
7411 holder
= entries
[i
].fService
;
7414 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7415 (void *) (uintptr_t) ns
, holder
,
7417 result
= kIOReturnSuccess
;
7421 IORecursiveLockUnlock(sCpuDelayLock
);
7426 #endif /* defined(__i386__) || defined(__x86_64__) */
7430 requireMaxBusStall(UInt32 __unused ns
)
7432 #if defined(__i386__) || defined(__x86_64__)
7433 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
7439 requireMaxInterruptDelay(uint32_t __unused ns
)
7441 #if defined(__i386__) || defined(__x86_64__)
7442 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
7451 IOService::resolveInterrupt(IOService
*nub
, int source
)
7453 IOInterruptController
*interruptController
;
7456 OSSymbol
*interruptControllerName
;
7458 IOInterruptSource
*interruptSources
;
7460 // Get the parents list from the nub.
7461 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
7462 if (array
== NULL
) {
7463 return kIOReturnNoResources
;
7466 // Allocate space for the IOInterruptSources if needed... then return early.
7467 if (nub
->_interruptSources
== NULL
) {
7468 numSources
= array
->getCount();
7469 interruptSources
= (IOInterruptSource
*)IOMalloc(
7470 numSources
* sizeofAllIOInterruptSource
);
7471 if (interruptSources
== NULL
) {
7472 return kIOReturnNoMemory
;
7475 bzero(interruptSources
, numSources
* sizeofAllIOInterruptSource
);
7477 nub
->_numInterruptSources
= numSources
;
7478 nub
->_interruptSources
= interruptSources
;
7479 return kIOReturnSuccess
;
7482 interruptControllerName
= OSDynamicCast(OSSymbol
, array
->getObject(source
));
7483 if (interruptControllerName
== NULL
) {
7484 return kIOReturnNoResources
;
7487 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
7488 if (interruptController
== NULL
) {
7489 return kIOReturnNoResources
;
7492 // Get the interrupt numbers from the nub.
7493 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
7494 if (array
== NULL
) {
7495 return kIOReturnNoResources
;
7497 data
= OSDynamicCast(OSData
, array
->getObject(source
));
7499 return kIOReturnNoResources
;
7502 // Set the interruptController and interruptSource in the nub's table.
7503 interruptSources
= nub
->_interruptSources
;
7504 interruptSources
[source
].interruptController
= interruptController
;
7505 interruptSources
[source
].vectorData
= data
;
7507 return kIOReturnSuccess
;
7511 IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
7515 /* Make sure the _interruptSources are set */
7516 if (_interruptSources
== NULL
) {
7517 ret
= resolveInterrupt(this, source
);
7518 if (ret
!= kIOReturnSuccess
) {
7523 /* Make sure the local source number is valid */
7524 if ((source
< 0) || (source
>= _numInterruptSources
)) {
7525 return kIOReturnNoInterrupt
;
7528 /* Look up the contoller for the local source */
7529 *interruptController
= _interruptSources
[source
].interruptController
;
7531 if (*interruptController
== NULL
) {
7533 return kIOReturnNoInterrupt
;
7536 /* Try to resolve the interrupt */
7537 ret
= resolveInterrupt(this, source
);
7538 if (ret
!= kIOReturnSuccess
) {
7542 *interruptController
= _interruptSources
[source
].interruptController
;
7545 return kIOReturnSuccess
;
7549 IOService::registerInterrupt(int source
, OSObject
*target
,
7550 IOInterruptAction handler
,
7553 IOInterruptController
*interruptController
;
7556 ret
= lookupInterrupt(source
, true, &interruptController
);
7557 if (ret
!= kIOReturnSuccess
) {
7561 /* Register the source */
7562 return interruptController
->registerInterrupt(this, source
, target
,
7563 (IOInterruptHandler
)handler
,
7568 IOServiceInterruptActionToBlock( OSObject
* target
, void * refCon
,
7569 IOService
* nub
, int source
)
7571 ((IOInterruptActionBlock
)(refCon
))(nub
, source
);
7575 IOService::registerInterruptBlock(int source
, OSObject
*target
,
7576 IOInterruptActionBlock handler
)
7581 block
= Block_copy(handler
);
7583 return kIOReturnNoMemory
;
7586 ret
= registerInterrupt(source
, target
, &IOServiceInterruptActionToBlock
, block
);
7587 if (kIOReturnSuccess
!= ret
) {
7588 Block_release(block
);
7591 _interruptSourcesPrivate(this)[source
].vectorBlock
= block
;
7597 IOService::unregisterInterrupt(int source
)
7600 IOInterruptController
*interruptController
;
7603 ret
= lookupInterrupt(source
, false, &interruptController
);
7604 if (ret
!= kIOReturnSuccess
) {
7608 /* Unregister the source */
7609 block
= _interruptSourcesPrivate(this)[source
].vectorBlock
;
7610 ret
= interruptController
->unregisterInterrupt(this, source
);
7611 if ((kIOReturnSuccess
== ret
) && (block
= _interruptSourcesPrivate(this)[source
].vectorBlock
)) {
7612 _interruptSourcesPrivate(this)[source
].vectorBlock
= NULL
;
7613 Block_release(block
);
7620 IOService::addInterruptStatistics(IOInterruptAccountingData
* statistics
, int source
)
7622 IOReportLegend
* legend
= NULL
;
7623 IOInterruptAccountingData
* oldValue
= NULL
;
7624 IOInterruptAccountingReporter
* newArray
= NULL
;
7625 char subgroupName
[64];
7626 int newArraySize
= 0;
7630 return kIOReturnBadArgument
;
7634 * We support statistics on a maximum of 256 interrupts per nub; if a nub
7635 * has more than 256 interrupt specifiers associated with it, and tries
7636 * to register a high interrupt index with interrupt accounting, panic.
7637 * Having more than 256 interrupts associated with a single nub is
7638 * probably a sign that something fishy is going on.
7640 if (source
> IA_INDEX_MAX
) {
7641 panic("addInterruptStatistics called for an excessively large index (%d)", source
);
7645 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
7646 * leaving it as is because the likelihood of contention where we are
7647 * actually growing the array is minimal (we would realistically need
7648 * to be starting a driver for the first time, with an IOReporting
7649 * client already in place). Nonetheless, cleanup that can be done
7650 * to adhere to best practices; it'll make the code more complicated,
7653 IOLockLock(reserved
->interruptStatisticsLock
);
7656 * Lazily allocate the statistics array.
7658 if (!reserved
->interruptStatisticsArray
) {
7659 reserved
->interruptStatisticsArray
= IONew(IOInterruptAccountingReporter
, 1);
7660 assert(reserved
->interruptStatisticsArray
);
7661 reserved
->interruptStatisticsArrayCount
= 1;
7662 bzero(reserved
->interruptStatisticsArray
, sizeof(*reserved
->interruptStatisticsArray
));
7665 if (source
>= reserved
->interruptStatisticsArrayCount
) {
7667 * We're still within the range of supported indices, but we are out
7668 * of space in the current array. Do a nasty realloc (because
7669 * IORealloc isn't a thing) here. We'll double the size with each
7672 * Yes, the "next power of 2" could be more efficient; but this will
7673 * be invoked incredibly rarely. Who cares.
7675 newArraySize
= (reserved
->interruptStatisticsArrayCount
<< 1);
7677 while (newArraySize
<= source
) {
7678 newArraySize
= (newArraySize
<< 1);
7680 newArray
= IONew(IOInterruptAccountingReporter
, newArraySize
);
7685 * TODO: This even zeroes the memory it is about to overwrite.
7686 * Shameful; fix it. Not particularly high impact, however.
7688 bzero(newArray
, newArraySize
* sizeof(*newArray
));
7689 memcpy(newArray
, reserved
->interruptStatisticsArray
, reserved
->interruptStatisticsArrayCount
* sizeof(*newArray
));
7690 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
7691 reserved
->interruptStatisticsArray
= newArray
;
7692 reserved
->interruptStatisticsArrayCount
= newArraySize
;
7695 if (!reserved
->interruptStatisticsArray
[source
].reporter
) {
7697 * We don't have a reporter associated with this index yet, so we
7698 * need to create one.
7701 * TODO: Some statistics do in fact have common units (time); should this be
7702 * split into separate reporters to communicate this?
7704 reserved
->interruptStatisticsArray
[source
].reporter
= IOSimpleReporter::with(this, kIOReportCategoryPower
, kIOReportUnitNone
);
7707 * Each statistic is given an identifier based on the interrupt index (which
7708 * should be unique relative to any single nub) and the statistic involved.
7709 * We should now have a sane (small and positive) index, so start
7710 * constructing the channels for statistics.
7712 for (i
= 0; i
< IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS
; i
++) {
7714 * TODO: Currently, this does not add channels for disabled statistics.
7715 * Will this be confusing for clients? If so, we should just add the
7716 * channels; we can avoid updating the channels even if they exist.
7718 if (IA_GET_STATISTIC_ENABLED(i
)) {
7719 reserved
->interruptStatisticsArray
[source
].reporter
->addChannel(IA_GET_CHANNEL_ID(source
, i
), kInterruptAccountingStatisticNameArray
[i
]);
7724 * We now need to add the legend for this reporter to the registry.
7726 OSObject
* prop
= copyProperty(kIOReportLegendKey
);
7727 legend
= IOReportLegend::with(OSDynamicCast(OSArray
, prop
));
7728 OSSafeReleaseNULL(prop
);
7731 * Note that while we compose the subgroup name, we do not need to
7732 * manage its lifecycle (the reporter will handle this).
7734 snprintf(subgroupName
, sizeof(subgroupName
), "%s %d", getName(), source
);
7735 subgroupName
[sizeof(subgroupName
) - 1] = 0;
7736 legend
->addReporterLegend(reserved
->interruptStatisticsArray
[source
].reporter
, kInterruptAccountingGroupName
, subgroupName
);
7737 setProperty(kIOReportLegendKey
, legend
->getLegend());
7741 * TODO: Is this a good idea? Probably not; my assumption is it opts
7742 * all entities who register interrupts into public disclosure of all
7743 * IOReporting channels. Unfortunately, this appears to be as fine
7746 setProperty(kIOReportLegendPublicKey
, true);
7750 * Don't stomp existing entries. If we are about to, panic; this
7751 * probably means we failed to tear down our old interrupt source
7754 oldValue
= reserved
->interruptStatisticsArray
[source
].statistics
;
7757 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source
);
7760 reserved
->interruptStatisticsArray
[source
].statistics
= statistics
;
7763 * Inherit the reporter values for each statistic. The target may
7764 * be torn down as part of the runtime of the service (especially
7765 * for sleep/wake), so we inherit in order to avoid having values
7766 * reset for no apparent reason. Our statistics are ultimately
7767 * tied to the index and the sevice, not to an individual target,
7768 * so we should maintain them accordingly.
7770 interruptAccountingDataInheritChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
7772 IOLockUnlock(reserved
->interruptStatisticsLock
);
7774 return kIOReturnSuccess
;
7778 IOService::removeInterruptStatistics(int source
)
7780 IOInterruptAccountingData
* value
= NULL
;
7783 return kIOReturnBadArgument
;
7786 IOLockLock(reserved
->interruptStatisticsLock
);
7789 * We dynamically grow the statistics array, so an excessively
7790 * large index value has NEVER been registered. This either
7791 * means our cap on the array size is too small (unlikely), or
7792 * that we have been passed a corrupt index (this must be passed
7793 * the plain index into the interrupt specifier list).
7795 if (source
>= reserved
->interruptStatisticsArrayCount
) {
7796 panic("removeInterruptStatistics called for index %d, which was never registered", source
);
7799 assert(reserved
->interruptStatisticsArray
);
7802 * If there is no existing entry, we are most likely trying to
7803 * free an interrupt owner twice, or we have corrupted the
7806 value
= reserved
->interruptStatisticsArray
[source
].statistics
;
7809 panic("removeInterruptStatistics called for empty index %d", source
);
7813 * We update the statistics, so that any delta with the reporter
7814 * state is not lost.
7816 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
7817 reserved
->interruptStatisticsArray
[source
].statistics
= NULL
;
7818 IOLockUnlock(reserved
->interruptStatisticsLock
);
7820 return kIOReturnSuccess
;
7824 IOService::getInterruptType(int source
, int *interruptType
)
7826 IOInterruptController
*interruptController
;
7829 ret
= lookupInterrupt(source
, true, &interruptController
);
7830 if (ret
!= kIOReturnSuccess
) {
7834 /* Return the type */
7835 return interruptController
->getInterruptType(this, source
, interruptType
);
7839 IOService::enableInterrupt(int source
)
7841 IOInterruptController
*interruptController
;
7844 ret
= lookupInterrupt(source
, false, &interruptController
);
7845 if (ret
!= kIOReturnSuccess
) {
7849 /* Enable the source */
7850 return interruptController
->enableInterrupt(this, source
);
7854 IOService::disableInterrupt(int source
)
7856 IOInterruptController
*interruptController
;
7859 ret
= lookupInterrupt(source
, false, &interruptController
);
7860 if (ret
!= kIOReturnSuccess
) {
7864 /* Disable the source */
7865 return interruptController
->disableInterrupt(this, source
);
7869 IOService::causeInterrupt(int source
)
7871 IOInterruptController
*interruptController
;
7874 ret
= lookupInterrupt(source
, false, &interruptController
);
7875 if (ret
!= kIOReturnSuccess
) {
7879 /* Cause an interrupt for the source */
7880 return interruptController
->causeInterrupt(this, source
);
7884 IOService::configureReport(IOReportChannelList
*channelList
,
7885 IOReportConfigureAction action
,
7891 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7892 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
7894 configurePowerStatesReport(action
, result
);
7896 return kIOReturnUnsupported
;
7898 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
7900 configureSimplePowerReport(action
, result
);
7902 return kIOReturnUnsupported
;
7907 IOLockLock(reserved
->interruptStatisticsLock
);
7909 /* The array count is signed (because the interrupt indices are signed), hence the cast */
7910 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
7911 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
7913 * If the reporter is currently associated with the statistics
7914 * for an event source, we may need to update the reporter.
7916 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
7917 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
7920 reserved
->interruptStatisticsArray
[cnt
].reporter
->configureReport(channelList
, action
, result
, destination
);
7924 IOLockUnlock(reserved
->interruptStatisticsLock
);
7926 return kIOReturnSuccess
;
7930 IOService::updateReport(IOReportChannelList
*channelList
,
7931 IOReportUpdateAction action
,
7937 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7938 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
7940 updatePowerStatesReport(action
, result
, destination
);
7942 return kIOReturnUnsupported
;
7944 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
7946 updateSimplePowerReport(action
, result
, destination
);
7948 return kIOReturnUnsupported
;
7953 IOLockLock(reserved
->interruptStatisticsLock
);
7955 /* The array count is signed (because the interrupt indices are signed), hence the cast */
7956 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
7957 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
7959 * If the reporter is currently associated with the statistics
7960 * for an event source, we need to update the reporter.
7962 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
7963 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
7966 reserved
->interruptStatisticsArray
[cnt
].reporter
->updateReport(channelList
, action
, result
, destination
);
7970 IOLockUnlock(reserved
->interruptStatisticsLock
);
7972 return kIOReturnSuccess
;
7976 IOService::getAuthorizationID( void )
7978 return reserved
->authorizationID
;
7982 IOService::setAuthorizationID( uint64_t authorizationID
)
7984 OSObject
* entitlement
;
7987 entitlement
= IOUserClient::copyClientEntitlement( current_task(), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
7990 if (entitlement
== kOSBooleanTrue
) {
7991 reserved
->authorizationID
= authorizationID
;
7993 status
= kIOReturnSuccess
;
7995 status
= kIOReturnNotPrivileged
;
7998 entitlement
->release();
8000 status
= kIOReturnNotPrivileged
;
8006 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8010 OSMetaClassDefineReservedUsed(IOService
, 0);
8011 OSMetaClassDefineReservedUsed(IOService
, 1);
8012 OSMetaClassDefineReservedUnused(IOService
, 2);
8013 OSMetaClassDefineReservedUnused(IOService
, 3);
8014 OSMetaClassDefineReservedUnused(IOService
, 4);
8015 OSMetaClassDefineReservedUnused(IOService
, 5);
8016 OSMetaClassDefineReservedUnused(IOService
, 6);
8017 OSMetaClassDefineReservedUnused(IOService
, 7);
8019 OSMetaClassDefineReservedUsed(IOService
, 0);
8020 OSMetaClassDefineReservedUsed(IOService
, 1);
8021 OSMetaClassDefineReservedUsed(IOService
, 2);
8022 OSMetaClassDefineReservedUsed(IOService
, 3);
8023 OSMetaClassDefineReservedUsed(IOService
, 4);
8024 OSMetaClassDefineReservedUsed(IOService
, 5);
8025 OSMetaClassDefineReservedUsed(IOService
, 6);
8026 OSMetaClassDefineReservedUsed(IOService
, 7);
8028 OSMetaClassDefineReservedUnused(IOService
, 8);
8029 OSMetaClassDefineReservedUnused(IOService
, 9);
8030 OSMetaClassDefineReservedUnused(IOService
, 10);
8031 OSMetaClassDefineReservedUnused(IOService
, 11);
8032 OSMetaClassDefineReservedUnused(IOService
, 12);
8033 OSMetaClassDefineReservedUnused(IOService
, 13);
8034 OSMetaClassDefineReservedUnused(IOService
, 14);
8035 OSMetaClassDefineReservedUnused(IOService
, 15);
8036 OSMetaClassDefineReservedUnused(IOService
, 16);
8037 OSMetaClassDefineReservedUnused(IOService
, 17);
8038 OSMetaClassDefineReservedUnused(IOService
, 18);
8039 OSMetaClassDefineReservedUnused(IOService
, 19);
8040 OSMetaClassDefineReservedUnused(IOService
, 20);
8041 OSMetaClassDefineReservedUnused(IOService
, 21);
8042 OSMetaClassDefineReservedUnused(IOService
, 22);
8043 OSMetaClassDefineReservedUnused(IOService
, 23);
8044 OSMetaClassDefineReservedUnused(IOService
, 24);
8045 OSMetaClassDefineReservedUnused(IOService
, 25);
8046 OSMetaClassDefineReservedUnused(IOService
, 26);
8047 OSMetaClassDefineReservedUnused(IOService
, 27);
8048 OSMetaClassDefineReservedUnused(IOService
, 28);
8049 OSMetaClassDefineReservedUnused(IOService
, 29);
8050 OSMetaClassDefineReservedUnused(IOService
, 30);
8051 OSMetaClassDefineReservedUnused(IOService
, 31);
8052 OSMetaClassDefineReservedUnused(IOService
, 32);
8053 OSMetaClassDefineReservedUnused(IOService
, 33);
8054 OSMetaClassDefineReservedUnused(IOService
, 34);
8055 OSMetaClassDefineReservedUnused(IOService
, 35);
8056 OSMetaClassDefineReservedUnused(IOService
, 36);
8057 OSMetaClassDefineReservedUnused(IOService
, 37);
8058 OSMetaClassDefineReservedUnused(IOService
, 38);
8059 OSMetaClassDefineReservedUnused(IOService
, 39);
8060 OSMetaClassDefineReservedUnused(IOService
, 40);
8061 OSMetaClassDefineReservedUnused(IOService
, 41);
8062 OSMetaClassDefineReservedUnused(IOService
, 42);
8063 OSMetaClassDefineReservedUnused(IOService
, 43);
8064 OSMetaClassDefineReservedUnused(IOService
, 44);
8065 OSMetaClassDefineReservedUnused(IOService
, 45);
8066 OSMetaClassDefineReservedUnused(IOService
, 46);
8067 OSMetaClassDefineReservedUnused(IOService
, 47);