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 _workLoopAction((IOWorkLoop::Action
) &actionWillStop
,
3027 victim
, (void *)(uintptr_t) options
, NULL
);
3030 OSArray
* notifiers
;
3031 notifiers
= victim
->copyNotifiers(gIOWillTerminateNotification
, 0, 0xffffffff);
3032 victim
->invokeNotifiers(¬ifiers
);
3034 _workLoopAction((IOWorkLoop::Action
) &actionWillTerminate
,
3036 (void *)(uintptr_t) options
,
3037 (void *)(uintptr_t) doPhase2List
,
3038 (void *)(uintptr_t) false);
3040 actionWillTerminate(
3041 victim
, options
, doPhase2List
, true, NULL
);
3043 didPhase2List
->headQ( victim
);
3046 victim
= (IOService
*) doPhase2List
->getObject(0);
3049 doPhase2List
->removeObject(0);
3053 while ((victim
= (IOService
*) didPhase2List
->getObject(0))) {
3054 bool scheduleFinalize
= false;
3055 if (victim
->lockForArbitration( true )) {
3056 victim
->__state
[1] |= kIOServiceTermPhase3State
;
3057 scheduleFinalize
= (NULL
== victim
->getClient());
3058 victim
->unlockForArbitration();
3060 _workLoopAction((IOWorkLoop::Action
) &actionDidTerminate
,
3061 victim
, (void *)(uintptr_t) options
);
3062 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
3063 _workLoopAction((IOWorkLoop::Action
) &actionDidStop
,
3064 victim
, (void *)(uintptr_t) options
, NULL
);
3066 // no clients - will go to finalize
3067 if (scheduleFinalize
) {
3068 victim
->scheduleFinalize(false);
3070 didPhase2List
->removeObject(0);
3072 IOLockLock( gJobsLock
);
3079 while ((victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
3080 bool sendFinal
= false;
3081 IOLockUnlock( gJobsLock
);
3082 if (victim
->lockForArbitration(true)) {
3083 sendFinal
= (0 == (victim
->__state
[1] & kIOServiceFinalized
));
3085 victim
->__state
[1] |= kIOServiceFinalized
;
3087 victim
->unlockForArbitration();
3090 _workLoopAction((IOWorkLoop::Action
) &actionFinalize
,
3091 victim
, (void *)(uintptr_t) options
);
3093 IOLockLock( gJobsLock
);
3095 freeList
->setObject( victim
);
3096 // safe if finalize list is append only
3097 gIOFinalizeList
->removeObject(0);
3101 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
));) {
3102 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
3105 uint64_t regID1
= provider
->getRegistryEntryID();
3106 uint64_t regID2
= client
->getRegistryEntryID();
3108 if (!provider
->isChild( client
, gIOServicePlane
)) {
3109 // may be multiply queued - nop it
3110 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
3112 IOSERVICE_TERMINATE_STOP_NOP
,
3114 (uintptr_t) (regID1
>> 32),
3116 (uintptr_t) (regID2
>> 32));
3118 // a terminated client is not ready for stop if it has clients, skip it
3119 bool deferStop
= (0 != (kIOServiceInactiveState
& client
->__state
[0]));
3120 IOLockUnlock( gJobsLock
);
3121 if (deferStop
&& client
->lockForArbitration(true)) {
3122 deferStop
= (0 == (client
->__state
[1] & kIOServiceFinalized
));
3123 //deferStop = (!deferStop && (0 != client->getClient()));
3124 //deferStop = (0 != client->getClient());
3125 client
->unlockForArbitration();
3127 TLOG("%s[0x%qx]::defer stop()\n", client
->getName(), regID2
);
3128 IOServiceTrace(IOSERVICE_TERMINATE_STOP_DEFER
,
3130 (uintptr_t) (regID1
>> 32),
3132 (uintptr_t) (regID2
>> 32));
3135 IOLockLock( gJobsLock
);
3139 _workLoopAction((IOWorkLoop::Action
) &actionStop
,
3140 provider
, (void *) client
);
3141 IOLockLock( gJobsLock
);
3142 // check the finalize list now
3146 freeList
->setObject( client
);
3147 freeList
->setObject( provider
);
3149 // safe if stop list is append only
3150 gIOStopList
->removeObject( idx
);
3151 gIOStopProviderList
->removeObject( idx
);
3156 gIOTerminateWork
-= workDone
;
3157 moreToDo
= (gIOTerminateWork
!= 0);
3160 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
3162 IOSERVICE_TERMINATE_DONE
,
3163 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
3167 IOLockUnlock( gJobsLock
);
3169 freeList
->release();
3170 doPhase2List
->release();
3171 didPhase2List
->release();
3173 IOLockLock( gJobsLock
);
3177 IOService::finalize( IOOptionBits options
)
3180 IOService
* provider
;
3181 uint64_t regID1
, regID2
= getRegistryEntryID();
3183 iter
= getProviderIterator();
3187 while ((provider
= (IOService
*) iter
->getNextObject())) {
3189 if (0 == (__state
[1] & kIOServiceTermPhase3State
)) {
3190 /* we come down here on programmatic terminate */
3192 regID1
= provider
->getRegistryEntryID();
3193 TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2
, provider
->getName(), regID1
);
3195 IOSERVICE_TERMINATE_STOP
,
3197 (uintptr_t) (regID1
>> 32),
3199 (uintptr_t) (regID2
>> 32));
3202 if (provider
->isOpen( this )) {
3203 provider
->close( this );
3208 if (provider
->lockForArbitration( true )) {
3209 if (0 == (provider
->__state
[1] & kIOServiceTermPhase3State
)) {
3210 scheduleStop( provider
);
3212 provider
->unlockForArbitration();
3230 IOService::doServiceTerminate( IOOptionBits options
)
3234 // a method in case someone needs to override it
3236 IOService::terminateClient( IOService
* client
, IOOptionBits options
)
3240 if (client
->isParent( this, gIOServicePlane
, true)) {
3241 // we are the clients only provider
3242 ok
= client
->terminate( options
);
3251 IOService::terminate( IOOptionBits options
)
3253 options
|= kIOServiceTerminate
;
3255 return terminatePhase1( options
);
3258 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3264 struct ServiceOpenMessageContext
{
3265 IOService
* service
;
3267 IOService
* excludeClient
;
3268 IOOptionBits options
;
3272 serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
3274 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
3276 if (object
!= context
->excludeClient
) {
3277 context
->service
->messageClient( context
->type
, object
, (void *)(uintptr_t) context
->options
);
3282 IOService::open( IOService
* forClient
,
3283 IOOptionBits options
,
3287 ServiceOpenMessageContext context
;
3289 context
.service
= this;
3290 context
.type
= kIOMessageServiceIsAttemptingOpen
;
3291 context
.excludeClient
= forClient
;
3292 context
.options
= options
;
3294 applyToInterested( gIOGeneralInterest
,
3295 &serviceOpenMessageApplier
, &context
);
3297 if (false == lockForArbitration(false)) {
3301 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
3303 ok
= handleOpen( forClient
, options
, arg
);
3306 if (ok
&& forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3307 forClient
->reserved
->uvars
->userServer
->serviceOpen(this, forClient
);
3310 unlockForArbitration();
3316 IOService::close( IOService
* forClient
,
3317 IOOptionBits options
)
3322 lockForArbitration();
3324 wasClosed
= handleIsOpen( forClient
);
3326 handleClose( forClient
, options
);
3327 last
= (__state
[1] & kIOServiceTermPhase3State
);
3329 if (forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3330 forClient
->reserved
->uvars
->userServer
->serviceClose(this, forClient
);
3334 unlockForArbitration();
3337 forClient
->scheduleStop( this );
3338 } else if (wasClosed
) {
3339 ServiceOpenMessageContext context
;
3341 context
.service
= this;
3342 context
.type
= kIOMessageServiceWasClosed
;
3343 context
.excludeClient
= forClient
;
3344 context
.options
= options
;
3346 applyToInterested( gIOGeneralInterest
,
3347 &serviceOpenMessageApplier
, &context
);
3352 IOService::isOpen( const IOService
* forClient
) const
3354 IOService
* self
= (IOService
*) this;
3357 self
->lockForArbitration();
3359 ok
= handleIsOpen( forClient
);
3361 self
->unlockForArbitration();
3367 IOService::handleOpen( IOService
* forClient
,
3368 IOOptionBits options
,
3373 ok
= (NULL
== __owner
);
3375 __owner
= forClient
;
3376 } else if (options
& kIOServiceSeize
) {
3377 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
3378 __owner
, (void *)(uintptr_t) options
));
3379 if (ok
&& (NULL
== __owner
)) {
3380 __owner
= forClient
;
3389 IOService::handleClose( IOService
* forClient
,
3390 IOOptionBits options
)
3392 if (__owner
== forClient
) {
3398 IOService::handleIsOpen( const IOService
* forClient
) const
3401 return __owner
== forClient
;
3403 return __owner
!= forClient
;
3408 * Probing & starting
3411 IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3413 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
3414 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
3422 val1
= obj1
->priority
;
3426 val2
= obj2
->priority
;
3433 IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
3435 OSDictionary
* dict
;
3436 IOService
* service
;
3437 _IOServiceNotifier
* notify
;
3438 OSSymbol
* key
= (OSSymbol
*) ref
;
3444 result
= kIODefaultProbeScore
;
3445 if ((dict
= OSDynamicCast( OSDictionary
, entry
))) {
3446 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
3447 } else if ((notify
= OSDynamicCast( _IOServiceNotifier
, entry
))) {
3448 return notify
->priority
;
3449 } else if ((service
= OSDynamicCast( IOService
, entry
))) {
3450 prop
= service
->copyProperty(key
);
3451 offset
= OSDynamicCast(OSNumber
, prop
);
3458 result
= offset
->unsigned32BitValue();
3461 OSSafeReleaseNULL(prop
);
3467 IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3469 const OSObject
* obj1
= (const OSObject
*) inObj1
;
3470 const OSObject
* obj2
= (const OSObject
*) inObj2
;
3478 val1
= IOServiceObjectOrder( obj1
, ref
);
3482 val2
= IOServiceObjectOrder( obj2
, ref
);
3489 IOService::copyClientWithCategory( const OSSymbol
* category
)
3491 IOService
* service
= NULL
;
3493 const OSSymbol
* nextCat
;
3495 iter
= getClientIterator();
3497 while ((service
= (IOService
*) iter
->getNextObject())) {
3498 if (kIOServiceInactiveState
& service
->__state
[0]) {
3501 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
3502 service
->getProperty( gIOMatchCategoryKey
));
3503 if (category
== nextCat
) {
3514 IOService::getClientWithCategory( const OSSymbol
* category
)
3517 service
= copyClientWithCategory(category
);
3525 IOService::invokeNotifier( _IOServiceNotifier
* notify
)
3527 _IOServiceNotifierInvocation invocation
;
3530 invocation
.thread
= current_thread();
3532 #if DEBUG_NOTIFIER_LOCKED
3534 if ((count
= isLockedForArbitration(0))) {
3535 IOLog("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3536 panic("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3538 #endif /* DEBUG_NOTIFIER_LOCKED */
3541 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
3544 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
3545 _IOServiceNotifierInvocation
*, link
);
3550 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
3553 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
3554 _IOServiceNotifierInvocation
*, link
);
3555 if (kIOServiceNotifyWaiter
& notify
->state
) {
3556 notify
->state
&= ~kIOServiceNotifyWaiter
;
3557 WAKEUPNOTIFY( notify
);
3566 IOService::invokeNotifiers(OSArray
* willSend
[])
3569 _IOServiceNotifier
* notify
;
3578 for (unsigned int idx
= 0;
3579 (notify
= (_IOServiceNotifier
*) array
->getObject(idx
));
3581 ret
&= invokeNotifier(notify
);
3590 * Alloc and probe matching classes,
3591 * called on the provider instance
3595 IOService::probeCandidates( OSOrderedSet
* matches
)
3597 OSDictionary
* match
= NULL
;
3600 IOService
* newInst
;
3601 OSDictionary
* props
;
3604 OSOrderedSet
* familyMatches
= NULL
;
3605 OSOrderedSet
* startList
;
3606 OSSet
* kexts
= NULL
;
3609 OSDictionary
* startDict
= NULL
;
3610 const OSSymbol
* category
;
3612 _IOServiceNotifier
* notify
;
3613 OSObject
* nextMatch
= NULL
;
3615 bool needReloc
= false;
3616 bool matchDeferred
= false;
3620 IOService
* client
= NULL
;
3623 OSDictionary
* rematchPersonality
;
3628 bool categoryConsumed
;
3632 prop1
= copyProperty(gIORematchPersonalityKey
);
3633 rematchPersonality
= OSDynamicCast(OSDictionary
, prop1
);
3634 if (rematchPersonality
) {
3635 prop2
= copyProperty(gIORematchCountKey
);
3636 num
= OSDynamicCast(OSNumber
, prop2
);
3638 count
= num
->unsigned32BitValue();
3640 OSSafeReleaseNULL(prop2
);
3646 && (nextMatch
= matches
->getFirstObject())) {
3647 nextMatch
->retain();
3648 matches
->removeObject(nextMatch
);
3650 if ((notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
3651 if (0 == (__state
[0] & kIOServiceInactiveState
)) {
3652 invokeNotifier( notify
);
3654 nextMatch
->release();
3657 } else if (!(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
3658 nextMatch
->release();
3665 debugFlags
= getDebugFlags( match
);
3669 isDext
= (NULL
!= match
->getObject(gIOUserServerNameKey
));
3670 if (isDext
&& !(kIODKEnable
& gIODKDebug
)) {
3674 category
= OSDynamicCast( OSSymbol
,
3675 match
->getObject( gIOMatchCategoryKey
));
3676 if (NULL
== category
) {
3677 category
= gIODefaultMatchCategoryKey
;
3679 client
= copyClientWithCategory(category
);
3681 categoryConsumed
= (client
!= NULL
);
3682 if (categoryConsumed
) {
3684 if ((debugFlags
& kIOLogMatch
) && (this != gIOResources
)) {
3685 LOG("%s: match category %s exists\n", getName(),
3686 category
->getCStringNoCopy());
3689 OSSafeReleaseNULL(client
);
3695 // create a copy now in case its modified during matching
3696 props
= OSDictionary::withDictionary(match
, match
->getCount());
3697 if (NULL
== props
) {
3700 props
->setCapacityIncrement(1);
3702 // check the nub matches
3703 if (false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
)) {
3708 if (categoryConsumed
) {
3713 if (rematchPersonality
) {
3714 bool personalityMatch
= match
->isEqualTo(rematchPersonality
);
3715 if (count
> gIODextRelaunchMax
) {
3716 personalityMatch
= !personalityMatch
;
3718 if (!personalityMatch
) {
3723 // Check to see if driver reloc has been loaded.
3724 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
, &kextRef
));
3727 if (debugFlags
& kIOLogCatalogue
) {
3728 LOG("%s: stalling for module\n", getName());
3731 // If reloc hasn't been loaded, exit;
3732 // reprobing will occur after reloc has been loaded.
3736 if (NULL
== kexts
) {
3737 kexts
= OSSet::withCapacity(1);
3740 kexts
->setObject(kextRef
);
3745 // copy saved for rematchng
3746 props
->setObject(gIOMatchedPersonalityKey
, match
);
3748 // reorder on family matchPropertyTable score.
3749 if (NULL
== familyMatches
) {
3750 familyMatches
= OSOrderedSet::withCapacity( 1,
3751 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3753 if (familyMatches
) {
3754 familyMatches
->setObject( props
);
3758 OSSafeReleaseNULL(nextMatch
);
3759 OSSafeReleaseNULL(props
);
3764 if (familyMatches
) {
3766 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
3768 familyMatches
->removeObject( props
);
3773 debugFlags
= getDebugFlags( props
);
3776 symbol
= OSDynamicCast( OSSymbol
,
3777 props
->getObject( gIOClassKey
));
3782 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), IOSERVICE_OBFUSCATE(symbol), IOSERVICE_OBFUSCATE(props));
3784 // alloc the driver instance
3785 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
3787 if (!inst
|| !OSDynamicCast(IOService
, inst
)) {
3788 IOLog("Couldn't alloc class \"%s\"\n",
3789 symbol
->getCStringNoCopy());
3793 // init driver instance
3794 if (!(inst
->init( props
))) {
3796 if (debugFlags
& kIOLogStart
) {
3797 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
3802 if (__state
[1] & kIOServiceSynchronousState
) {
3803 inst
->__state
[1] |= kIOServiceSynchronousState
;
3806 // give the driver the default match category if not specified
3807 category
= OSDynamicCast( OSSymbol
,
3808 props
->getObject( gIOMatchCategoryKey
));
3809 if (NULL
== category
) {
3810 category
= gIODefaultMatchCategoryKey
;
3812 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
3813 // attach driver instance
3814 if (!(inst
->attach( this ))) {
3818 // pass in score from property table
3819 score
= familyMatches
->orderObject( props
);
3821 // & probe the new driver instance
3823 if (debugFlags
& kIOLogProbe
) {
3824 LOG("%s::probe(%s)\n",
3825 inst
->getMetaClass()->getClassName(), getName());
3829 newInst
= inst
->probe( this, &score
);
3830 inst
->detach( this );
3831 if (NULL
== newInst
) {
3833 if (debugFlags
& kIOLogProbe
) {
3834 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
3841 newPri
= OSNumber::withNumber( score
, 32 );
3843 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
3847 // add to start list for the match category
3848 if (NULL
== startDict
) {
3849 startDict
= OSDictionary::withCapacity( 1 );
3851 assert( startDict
);
3852 startList
= (OSOrderedSet
*)
3853 startDict
->getObject( category
);
3854 if (NULL
== startList
) {
3855 startList
= OSOrderedSet::withCapacity( 1,
3856 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3857 if (startDict
&& startList
) {
3858 startDict
->setObject( category
, startList
);
3859 startList
->release();
3862 assert( startList
);
3864 startList
->setObject( newInst
);
3873 familyMatches
->release();
3874 familyMatches
= NULL
;
3877 // start the best (until success) of each category
3879 iter
= OSCollectionIterator::withCollection( startDict
);
3881 while ((category
= (const OSSymbol
*) iter
->getNextObject())) {
3882 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
3883 assert( startList
);
3889 while (true // (!started)
3891 && (inst
= (IOService
*)startList
->getFirstObject())) {
3893 startList
->removeObject(inst
);
3896 debugFlags
= getDebugFlags( inst
);
3898 if (debugFlags
& kIOLogStart
) {
3900 LOG( "match category exists, skipping " );
3902 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
3903 getName(), inst
->getRetainCount());
3906 if (false == started
) {
3908 IOLockLock(gJobsLock
);
3909 matchDeferred
= (gIOMatchDeferList
3910 && (kOSBooleanTrue
== inst
->getProperty(gIOMatchDeferKey
)));
3911 if (matchDeferred
&& (-1U == gIOMatchDeferList
->getNextIndexOfObject(this, 0))) {
3912 gIOMatchDeferList
->setObject(this);
3914 IOLockUnlock(gJobsLock
);
3915 if (matchDeferred
) {
3916 symbol
= OSDynamicCast(OSSymbol
, inst
->getProperty(gIOClassKey
));
3917 IOLog("%s(0x%qx): matching deferred by %s\n",
3918 getName(), getRegistryEntryID(),
3919 symbol
? symbol
->getCStringNoCopy() : "");
3920 // rematching will occur after kextd loads all plists
3923 if (!matchDeferred
) {
3924 started
= startCandidate( inst
);
3926 if ((debugFlags
& kIOLogStart
) && (false == started
)) {
3927 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
3928 inst
->getRetainCount());
3939 OSSafeReleaseNULL(prop1
);
3942 num
= OSNumber::withNumber(dextCount
, 32);
3943 setProperty(gIODEXTMatchCountKey
, num
);
3944 OSSafeReleaseNULL(num
);
3945 } else if (rematchPersonality
) {
3946 removeProperty(gIODEXTMatchCountKey
);
3949 // now that instances are created, drop the refs on any kexts allowing unload
3951 OSKext::dropMatchingReferences(kexts
);
3952 OSSafeReleaseNULL(kexts
);
3955 // adjust the busy count by +1 if matching is stalled for a module,
3956 // or -1 if a previously stalled matching is complete.
3957 lockForArbitration();
3959 uint64_t regID
= getRegistryEntryID();
3962 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
3965 IOSERVICE_MODULESTALL
,
3967 (uintptr_t) (regID
>> 32),
3971 __state
[1] |= kIOServiceModuleStallState
;
3973 } else if (__state
[1] & kIOServiceModuleStallState
) {
3975 IOSERVICE_MODULEUNSTALL
,
3977 (uintptr_t) (regID
>> 32),
3981 __state
[1] &= ~kIOServiceModuleStallState
;
3985 _adjustBusy( adjBusy
);
3987 unlockForArbitration();
3990 startDict
->release();
3995 * Wait for a IOUserServer to check in
3999 __attribute__((noinline
, not_tail_called
))
4001 __WAITING_FOR_USER_SERVER__(OSDictionary
* matching
)
4004 server
= IOService::waitForMatchingService(matching
, kIOUserServerCheckInTimeoutSecs
* NSEC_PER_SEC
);
4009 IOService::willShutdown()
4011 gKextdWillTerminate
= true;
4013 getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
4015 OSKext::willShutdown();
4018 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4021 IOServicePH::init(IOPMrootDomain
* root
)
4023 fUserServers
= OSArray::withCapacity(4);
4024 fMatchingWork
= OSArray::withCapacity(4);
4026 assert(fUserServers
&& fMatchingWork
);
4028 fRootNotifier
= root
->registerInterest(
4029 gIOPriorityPowerStateInterest
, &IOServicePH::systemPowerChange
, NULL
, NULL
);
4031 assert(fRootNotifier
);
4037 IOLockLock(gJobsLock
);
4041 IOServicePH::unlock()
4043 IOLockUnlock(gJobsLock
);
4047 IOServicePH::serverAdd(IOUserServer
* server
)
4052 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4054 fUserServers
->setObject(server
);
4060 IOServicePH::serverRemove(IOUserServer
* server
)
4065 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4067 fUserServers
->removeObject(idx
);
4073 IOServicePH::serverAck(IOUserServer
* server
)
4081 if (server
&& fUserServersWait
) {
4082 idx
= fUserServersWait
->getNextIndexOfObject(server
, 0);
4084 fUserServersWait
->removeObject(idx
);
4085 if (0 == fUserServersWait
->getCount()) {
4086 OSSafeReleaseNULL(fUserServersWait
);
4090 if (!fUserServersWait
&& !fMatchingWork
->getCount()) {
4091 ackTo
= fSystemPowerAckTo
;
4092 ackToRef
= fSystemPowerAckRef
;
4093 fSystemPowerAckTo
= NULL
;
4098 DKLOG("allowPowerChange\n");
4099 ackTo
->allowPowerChange((uintptr_t) ackToRef
);
4104 IOServicePH::matchingStart(IOService
* service
)
4112 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4114 fMatchingWork
->setObject(service
);
4117 if (!fMatchingDelayed
) {
4118 fMatchingDelayed
= OSArray::withObjects((const OSObject
**) &service
, 1, 1);
4120 idx
= fMatchingDelayed
->getNextIndexOfObject(service
, 0);
4122 fMatchingDelayed
->setObject(service
);
4132 IOServicePH::matchingEnd(IOService
* service
)
4135 OSArray
* notifyServers
;
4136 OSArray
* deferredMatches
;
4138 notifyServers
= NULL
;
4139 deferredMatches
= NULL
;
4144 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4146 fMatchingWork
->removeObject(idx
);
4151 if ((fUserServerOff
!= fSystemOff
) && fUserServers
->getCount()) {
4153 if (0 == fMatchingWork
->getCount()) {
4154 fUserServersWait
= OSArray::withArray(fUserServers
);
4155 notifyServers
= OSArray::withArray(fUserServers
);
4156 fUserServerOff
= fSystemOff
;
4159 notifyServers
= OSArray::withArray(fUserServers
);
4160 fUserServerOff
= fSystemOff
;
4164 if (!fSystemOff
&& fMatchingDelayed
) {
4165 deferredMatches
= fMatchingDelayed
;
4166 fMatchingDelayed
= NULL
;
4171 if (notifyServers
) {
4172 notifyServers
->iterateObjects(^bool (OSObject
* obj
) {
4174 us
= (typeof(us
))obj
;
4175 us
->systemPower(fSystemOff
);
4178 OSSafeReleaseNULL(notifyServers
);
4181 if (deferredMatches
) {
4182 DKLOG("sleep deferred rematching count %d\n", deferredMatches
->getCount());
4183 deferredMatches
->iterateObjects(^bool (OSObject
* obj
)
4185 ((IOService
*)obj
)->startMatching(kIOServiceAsynchronous
);
4188 deferredMatches
->release();
4195 IOServicePH::systemPowerChange(
4198 UInt32 messageType
, IOService
* service
,
4199 void * messageArgument
, vm_size_t argSize
)
4203 IOPMSystemCapabilityChangeParameters
* params
;
4207 switch (messageType
) {
4208 case kIOMessageSystemCapabilityChange
:
4210 params
= (typeof params
)messageArgument
;
4212 if (kIODKLogPM
& gIODKDebug
) {
4213 IOLog("IOServicePH::kIOMessageSystemCapabilityChange: %s%s 0x%x->0x%x\n",
4214 params
->changeFlags
& kIOPMSystemCapabilityWillChange
? "will" : "",
4215 params
->changeFlags
& kIOPMSystemCapabilityDidChange
? "did" : "",
4216 params
->fromCapabilities
,
4217 params
->toCapabilities
);
4220 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4221 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
4222 ((params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)) {
4225 fSystemPowerAckRef
= params
->notifyRef
;
4226 fSystemPowerAckTo
= service
;
4231 params
->maxWaitForReply
= 60 * 1000 * 1000;
4232 ret
= kIOReturnSuccess
;
4233 } else if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4234 ((params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0) &&
4235 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
)) {
4242 params
->maxWaitForReply
= 0;
4243 ret
= kIOReturnSuccess
;
4245 params
->maxWaitForReply
= 0;
4246 ret
= kIOReturnSuccess
;
4251 ret
= kIOReturnUnsupported
;
4258 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4261 * Start a previously attached & probed instance,
4262 * called on exporting object instance
4266 IOService::startCandidate( IOService
* service
)
4271 IOUserServer
* userServer
;
4275 obj
= service
->copyProperty(gIOUserServerNameKey
);
4277 if (obj
&& (this == gIOResources
)) {
4280 ok
= service
->attach( this );
4286 if ((this != gIOResources
) && (this != gIOUserResources
)) {
4287 // stall for any nub resources
4289 // stall for any driver resources
4290 service
->checkResources();
4294 OSString
* bundleID
;
4295 OSString
* serverName
;
4297 const OSSymbol
* sym
;
4298 OSDictionary
* matching
;
4300 OSNumber
* serverTag
;
4303 if ((serverName
= OSDynamicCast(OSString
, obj
))) {
4304 obj
= service
->copyProperty(gIOModuleIdentifierKey
);
4305 bundleID
= OSDynamicCast(OSString
, obj
);
4306 entryID
= service
->getRegistryEntryID();
4307 serverTag
= OSNumber::withNumber(entryID
, 64);
4309 if (gKextdWillTerminate
) {
4310 DKLOG("%s disabled in shutdown\n", serverName
->getCStringNoCopy());
4311 service
->detach(this);
4312 OSSafeReleaseNULL(obj
);
4316 ph
= IOServicePH::matchingStart(this);
4318 DKLOG("%s deferred in sleep\n", serverName
->getCStringNoCopy());
4319 service
->detach(this);
4320 OSSafeReleaseNULL(obj
);
4324 prop
= service
->copyProperty(gIOUserClassKey
);
4325 str
= OSDynamicCast(OSString
, prop
);
4327 service
->setName(str
);
4329 OSSafeReleaseNULL(prop
);
4331 if (!(kIODKDisableDextLaunch
& gIODKDebug
)) {
4332 OSKext::requestDaemonLaunch(bundleID
, serverName
, serverTag
);
4334 sym
= OSSymbol::withString(serverName
);
4335 matching
= serviceMatching(gIOUserServerClassKey
);
4336 propertyMatching(gIOUserServerNameKey
, sym
, matching
);
4337 if (!(kIODKDisableDextTag
& gIODKDebug
)) {
4338 propertyMatching(gIOUserServerTagKey
, serverTag
, matching
);
4341 server
= __WAITING_FOR_USER_SERVER__(matching
);
4342 matching
->release();
4343 OSSafeReleaseNULL(serverTag
);
4344 OSSafeReleaseNULL(serverName
);
4346 userServer
= OSDynamicCast(IOUserServer
, server
);
4348 service
->detach(this);
4349 IOServicePH::matchingEnd(this);
4350 DKLOG(DKS
" user server timeout\n", DKN(service
));
4354 if (!(kIODKDisableCDHashChecking
& gIODKDebug
)) {
4355 if (!userServer
->serviceMatchesCDHash(service
)) {
4356 service
->detach(this);
4357 IOServicePH::matchingEnd(this);
4358 userServer
->exit("CDHash check failed");
4359 userServer
->release();
4363 OSKext
*kext
= OSKext::lookupKextWithIdentifier(bundleID
);
4365 const char *name
= bundleID
->getCStringNoCopy();
4366 IOLog("%s Could not find OSKext for %s\n", __func__
, name
);
4373 userServer
->setTaskLoadTag(kext
);
4374 userServer
->setDriverKitUUID(kext
);
4375 OSKext::OSKextLogDriverKitInfoLoad(kext
);
4377 OSSafeReleaseNULL(bundleID
);
4378 OSSafeReleaseNULL(kext
);
4380 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
4381 if (!userServer
->checkEntitlements(this, service
)) {
4382 service
->detach(this);
4383 IOServicePH::matchingEnd(this);
4384 userServer
->exit("Entitlements check failed");
4385 userServer
->release();
4390 userServer
->serviceAttach(service
, this);
4394 AbsoluteTime startTime
;
4395 AbsoluteTime endTime
;
4398 if (kIOLogStart
& gIOKitDebug
) {
4399 clock_get_uptime(&startTime
);
4402 ok
= service
->start(this);
4404 if (kIOLogStart
& gIOKitDebug
) {
4405 clock_get_uptime(&endTime
);
4407 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0) {
4408 SUB_ABSOLUTETIME(&endTime
, &startTime
);
4409 absolutetime_to_nanoseconds(endTime
, &nano
);
4410 if (nano
> 500000000ULL) {
4411 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
4416 userServer
->serviceStarted(service
, this, ok
);
4417 userServer
->release();
4420 service
->detach( this );
4424 IOServicePH::matchingEnd(this);
4431 IOService::publishResource( const char * key
, OSObject
* value
)
4433 const OSSymbol
* sym
;
4435 if ((sym
= OSSymbol::withCString( key
))) {
4436 publishResource( sym
, value
);
4442 IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
4444 if (NULL
== value
) {
4445 value
= (OSObject
*) gIOServiceKey
;
4448 gIOResources
->setProperty( key
, value
);
4450 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4454 gIOResourceGenerationCount
++;
4455 gIOResources
->registerService();
4459 IOService::publishUserResource( const OSSymbol
* key
, OSObject
* value
)
4461 if (NULL
== value
) {
4462 value
= (OSObject
*) gIOServiceKey
;
4465 gIOUserResources
->setProperty( key
, value
);
4467 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4471 gIOResourceGenerationCount
++;
4472 gIOUserResources
->registerService();
4476 IOService::addNeededResource( const char * key
)
4478 OSObject
* resourcesProp
;
4483 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4484 if (!resourcesProp
) {
4488 newKey
= OSString::withCString( key
);
4490 resourcesProp
->release();
4494 set
= OSDynamicCast( OSSet
, resourcesProp
);
4496 set
= OSSet::withCapacity( 1 );
4498 set
->setObject( resourcesProp
);
4504 set
->setObject( newKey
);
4506 ret
= setProperty( gIOResourceMatchKey
, set
);
4508 resourcesProp
->release();
4514 IOService::checkResource( OSObject
* matching
)
4517 OSDictionary
* table
;
4519 if ((str
= OSDynamicCast( OSString
, matching
))) {
4520 if (gIOResources
->getProperty( str
)) {
4526 table
= resourceMatching( str
);
4527 } else if ((table
= OSDynamicCast( OSDictionary
, matching
))) {
4530 IOLog("%s: Can't match using: %s\n", getName(),
4531 matching
->getMetaClass()->getClassName());
4532 /* false would stall forever */
4536 if (gIOKitDebug
& kIOLogConfig
) {
4537 LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName());
4540 waitForService( table
);
4542 if (gIOKitDebug
& kIOLogConfig
) {
4543 LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
4550 IOService::checkResources( void )
4552 OSObject
* resourcesProp
;
4557 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4558 if (NULL
== resourcesProp
) {
4562 if ((set
= OSDynamicCast( OSSet
, resourcesProp
))) {
4563 iter
= OSCollectionIterator::withCollection( set
);
4564 ok
= (NULL
!= iter
);
4565 while (ok
&& (resourcesProp
= iter
->getNextObject())) {
4566 ok
= checkResource( resourcesProp
);
4572 ok
= checkResource( resourcesProp
);
4575 OSSafeReleaseNULL(resourcesProp
);
4582 _IOConfigThread::configThread( int configThreadId
)
4584 _IOConfigThread
* inst
;
4587 if (!(inst
= new _IOConfigThread
)) {
4590 if (!inst
->init()) {
4594 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &thread
)) {
4598 char threadName
[MAXTHREADNAMESIZE
];
4599 snprintf(threadName
, sizeof(threadName
), "IOConfigThread_%d", configThreadId
);
4600 thread_set_thread_name(thread
, threadName
);
4601 thread_deallocate(thread
);
4614 IOService::doServiceMatch( IOOptionBits options
)
4616 _IOServiceNotifier
* notify
;
4618 OSOrderedSet
* matches
;
4619 OSArray
* resourceKeys
= NULL
;
4620 SInt32 catalogGeneration
;
4621 bool keepGuessing
= true;
4622 bool reRegistered
= true;
4624 OSArray
* notifiers
[2] = {NULL
};
4626 // job->nub->deliverNotification( gIOPublishNotification,
4627 // kIOServiceRegisteredState, 0xffffffff );
4629 while (keepGuessing
) {
4630 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
4631 // the matches list should always be created by findDrivers()
4633 lockForArbitration();
4634 if (0 == (__state
[0] & kIOServiceFirstPublishState
)) {
4635 getMetaClass()->addInstance(this);
4636 notifiers
[0] = copyNotifiers(gIOFirstPublishNotification
,
4637 kIOServiceFirstPublishState
, 0xffffffff );
4640 __state
[1] &= ~kIOServiceNeedConfigState
;
4641 __state
[1] |= kIOServiceConfigState
| kIOServiceConfigRunning
;
4642 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
4643 __state
[0] |= kIOServiceRegisteredState
;
4645 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
4646 if (reRegistered
&& keepGuessing
) {
4647 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
4648 gNotifications
->getObject( gIOPublishNotification
));
4650 while ((notify
= (_IOServiceNotifier
*)
4651 iter
->getNextObject())) {
4652 if (matchPassive(notify
->matching
, 0)
4653 && (kIOServiceNotifyEnable
& notify
->state
)) {
4654 matches
->setObject( notify
);
4662 unlockForArbitration();
4663 invokeNotifiers(¬ifiers
[0]);
4665 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources())) {
4666 if ((this == gIOResources
) || (this == gIOUserResources
)) {
4668 resourceKeys
->release();
4670 resourceKeys
= copyPropertyKeys();
4672 probeCandidates( matches
);
4678 lockForArbitration();
4679 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
4681 (reRegistered
|| (catalogGeneration
!=
4682 gIOCatalogue
->getGenerationCount()))
4683 && (0 == (__state
[0] & kIOServiceInactiveState
));
4686 unlockForArbitration();
4690 if ((0 == (__state
[0] & kIOServiceInactiveState
))
4691 && (0 == (__state
[1] & kIOServiceModuleStallState
))) {
4693 setProperty(gIOResourceMatchedKey
, resourceKeys
);
4696 notifiers
[0] = copyNotifiers(gIOMatchedNotification
,
4697 kIOServiceMatchedState
, 0xffffffff);
4698 if (0 == (__state
[0] & kIOServiceFirstMatchState
)) {
4699 notifiers
[1] = copyNotifiers(gIOFirstMatchNotification
,
4700 kIOServiceFirstMatchState
, 0xffffffff);
4704 __state
[1] &= ~kIOServiceConfigRunning
;
4705 unlockForArbitration();
4708 resourceKeys
->release();
4711 invokeNotifiers(¬ifiers
[0]);
4712 invokeNotifiers(¬ifiers
[1]);
4714 lockForArbitration();
4715 __state
[1] &= ~kIOServiceConfigState
;
4716 scheduleTerminatePhase2();
4719 unlockForArbitration();
4723 IOService::_adjustBusy( SInt32 delta
)
4728 bool wasQuiet
, nowQuiet
, needWake
;
4731 result
= __state
[1] & kIOServiceBusyStateMask
;
4736 next
->lockForArbitration();
4738 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
4739 wasQuiet
= (0 == count
);
4740 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
))) {
4741 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
4745 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
4746 nowQuiet
= (0 == count
);
4747 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
4750 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
4751 IOLockLock( gIOServiceBusyLock
);
4752 thread_wakeup((event_t
) next
);
4753 IOLockUnlock( gIOServiceBusyLock
);
4756 next
->unlockForArbitration();
4759 if ((wasQuiet
|| nowQuiet
)) {
4760 uint64_t regID
= next
->getRegistryEntryID();
4762 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
4764 (uintptr_t) (regID
>> 32),
4769 next
->__timeBusy
= mach_absolute_time();
4771 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
4772 next
->__timeBusy
= 0;
4775 MessageClientsContext context
;
4777 context
.service
= next
;
4778 context
.type
= kIOMessageServiceBusyStateChange
;
4779 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
4780 context
.argSize
= 0;
4782 applyToInterestNotifiers( next
, gIOBusyInterest
,
4783 &messageClientsApplier
, &context
);
4786 if (nowQuiet
&& (next
== gIOServiceRoot
)) {
4787 OSKext::considerUnloads();
4788 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
4793 delta
= nowQuiet
? -1 : +1;
4794 } while ((wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
4801 IOService::adjustBusy( SInt32 delta
)
4803 lockForArbitration();
4804 _adjustBusy( delta
);
4805 unlockForArbitration();
4809 IOService::getAccumulatedBusyTime( void )
4811 uint64_t accumBusy
= __accumBusy
;
4812 uint64_t timeBusy
= __timeBusy
;
4816 accumBusy
= __accumBusy
;
4817 timeBusy
= __timeBusy
;
4819 accumBusy
+= mach_absolute_time() - timeBusy
;
4821 }while (timeBusy
!= __timeBusy
);
4823 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
4829 IOService::getBusyState( void )
4831 return __state
[1] & kIOServiceBusyStateMask
;
4835 IOService::waitForState( UInt32 mask
, UInt32 value
,
4836 mach_timespec_t
* timeout
)
4838 panic("waitForState");
4839 return kIOReturnUnsupported
;
4843 IOService::waitForState( UInt32 mask
, UInt32 value
,
4847 int waitResult
= THREAD_AWAKENED
;
4848 bool computeDeadline
= true;
4849 AbsoluteTime abstime
;
4852 lockForArbitration();
4853 IOLockLock( gIOServiceBusyLock
);
4854 wait
= (value
!= (__state
[1] & mask
));
4856 __state
[1] |= kIOServiceBusyWaiterState
;
4857 unlockForArbitration();
4858 if (timeout
!= UINT64_MAX
) {
4859 if (computeDeadline
) {
4860 AbsoluteTime nsinterval
;
4861 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
4862 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
4863 computeDeadline
= false;
4865 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
4867 assert_wait((event_t
)this, THREAD_UNINT
);
4870 unlockForArbitration();
4872 IOLockUnlock( gIOServiceBusyLock
);
4874 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
4876 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
4878 if (waitResult
== THREAD_TIMED_OUT
) {
4879 return kIOReturnTimeout
;
4881 return kIOReturnSuccess
;
4886 IOService::waitQuiet( uint64_t timeout
)
4890 char * string
= NULL
;
4891 char * panicString
= NULL
;
4893 size_t panicStringLen
;
4901 * On kasan kernels, everything takes longer, so double the number of
4902 * timeout extensions. This should help with issues like 41259215
4903 * where WindowServer was timing out waiting for kextd to get all the
4904 * kasan kexts loaded and started.
4906 enum { kTimeoutExtensions
= 8 };
4908 enum { kTimeoutExtensions
= 4 };
4911 time
= mach_absolute_time();
4913 for (loops
= 0; loops
< kTimeoutExtensions
; loops
++) {
4914 ret
= waitForState( kIOServiceBusyStateMask
, 0, timeout
);
4916 if (loops
&& (kIOReturnSuccess
== ret
)) {
4917 time
= mach_absolute_time() - time
;
4918 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&time
, &nano
);
4919 IOLog("busy extended ok[%d], (%llds, %llds)\n",
4920 loops
, timeout
/ 1000000000ULL, nano
/ 1000000000ULL);
4922 } else if (kIOReturnTimeout
!= ret
) {
4924 } else if (timeout
< (4100ull * NSEC_PER_SEC
)) {
4929 IORegistryIterator
* iter
;
4931 OSOrderedSet
* leaves
;
4933 IOService
* nextParent
;
4938 panicStringLen
= 256;
4940 string
= IONew(char, len
);
4943 panicString
= IONew(char, panicStringLen
);
4946 kextdWait
= OSKext::isWaitingKextd();
4947 iter
= IORegistryIterator::iterateOver(this, gIOServicePlane
, kIORegistryIterateRecursively
);
4948 leaves
= OSOrderedSet::withCapacity(4);
4950 set
= iter
->iterateAll();
4952 if (string
&& panicString
&& leaves
&& set
) {
4953 string
[0] = panicString
[0] = 0;
4954 set
->setObject(this);
4955 while ((next
= (IOService
*) set
->getLastObject())) {
4956 if (next
->getBusyState()) {
4957 if (kIOServiceModuleStallState
& next
->__state
[1]) {
4960 leaves
->setObject(next
);
4962 while ((nextParent
= nextParent
->getProvider())) {
4963 set
->removeObject(nextParent
);
4964 leaves
->removeObject(nextParent
);
4967 set
->removeObject(next
);
4970 while ((next
= (IOService
*) leaves
->getLastObject())) {
4971 l
= snprintf(s
, len
, "%s'%s'", ((s
== string
) ? "" : ", "), next
->getName());
4977 leaves
->removeObject(next
);
4980 OSSafeReleaseNULL(leaves
);
4981 OSSafeReleaseNULL(set
);
4982 OSSafeReleaseNULL(iter
);
4985 dopanic
= ((loops
>= (kTimeoutExtensions
- 1)) && (kIOWaitQuietPanics
& gIOKitDebug
));
4986 snprintf(panicString
, panicStringLen
,
4987 "%s[%d], (%llds): %s",
4988 kextdWait
? "kextd stall" : "busy timeout",
4989 loops
, timeout
/ 1000000000ULL,
4990 string
? string
: "");
4991 IOLog("%s\n", panicString
);
4993 panic("%s", panicString
);
4994 } else if (!loops
) {
4995 getPMRootDomain()->startSpinDump(1);
5000 IODelete(string
, char, 256);
5003 IODelete(panicString
, char, panicStringLen
);
5010 IOService::waitQuiet( mach_timespec_t
* timeout
)
5015 timeoutNS
= timeout
->tv_sec
;
5016 timeoutNS
*= kSecondScale
;
5017 timeoutNS
+= timeout
->tv_nsec
;
5019 timeoutNS
= UINT64_MAX
;
5022 return waitQuiet(timeoutNS
);
5026 IOService::serializeProperties( OSSerialize
* s
) const
5029 ((IOService
*)this)->setProperty(((IOService
*)this)->__state
,
5030 sizeof(__state
), "__state");
5032 return super::serializeProperties(s
);
5037 _IOConfigThread::main(void * arg
, wait_result_t result
)
5039 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
5040 _IOServiceJob
* job
;
5044 thread_precedence_policy_data_t precedence
= { -1 };
5046 kr
= thread_policy_set(current_thread(),
5047 THREAD_PRECEDENCE_POLICY
,
5048 (thread_policy_t
) &precedence
,
5049 THREAD_PRECEDENCE_POLICY_COUNT
);
5050 if (KERN_SUCCESS
!= kr
) {
5051 IOLog("thread_policy_set(%d)\n", kr
);
5057 semaphore_wait( gJobsSemaphore
);
5059 IOTakeLock( gJobsLock
);
5060 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
5062 gJobs
->removeObject(job
);
5065 // gNumConfigThreads--; // we're out of service
5066 gNumWaitingThreads
--; // we're out of service
5068 IOUnlock( gJobsLock
);
5073 if (gIOKitDebug
& kIOLogConfig
) {
5074 LOG("config(%p): starting on %s, %d\n",
5075 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->nub
->getName(), job
->type
);
5078 switch (job
->type
) {
5080 nub
->doServiceMatch( job
->options
);
5084 LOG("config(%p): strange type (%d)\n",
5085 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->type
);
5092 IOTakeLock( gJobsLock
);
5093 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
5095 gNumWaitingThreads
++; // back in service
5097 // gNumConfigThreads++;
5099 if (0 == --gNumConfigThreads
) {
5100 // IOLog("MATCH IDLE\n");
5101 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
5104 IOUnlock( gJobsLock
);
5108 if (gIOKitDebug
& kIOLogConfig
) {
5109 LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5116 IOService::waitMatchIdle( UInt32 msToWait
)
5119 int waitResult
= THREAD_AWAKENED
;
5120 bool computeDeadline
= true;
5121 AbsoluteTime deadline
;
5123 IOLockLock( gJobsLock
);
5125 wait
= (0 != gNumConfigThreads
);
5128 if (computeDeadline
) {
5129 clock_interval_to_deadline(
5130 msToWait
, kMillisecondScale
, &deadline
);
5131 computeDeadline
= false;
5133 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
5134 deadline
, THREAD_UNINT
);
5136 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
5140 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
5141 IOLockUnlock( gJobsLock
);
5143 if (waitResult
== THREAD_TIMED_OUT
) {
5144 return kIOReturnTimeout
;
5146 return kIOReturnSuccess
;
5151 IOService::cpusRunning(void)
5153 gCPUsRunning
= true;
5157 _IOServiceJob::pingConfig( _IOServiceJob
* job
)
5164 IOTakeLock( gJobsLock
);
5167 gJobs
->setLastObject( job
);
5169 count
= gNumWaitingThreads
;
5170 // if( gNumConfigThreads) count++;// assume we're called from a config thread
5172 create
= ((gOutstandingJobs
> count
)
5173 && ((gNumConfigThreads
< kMaxConfigThreads
)
5174 || (job
->nub
== gIOResources
)
5177 gNumConfigThreads
++;
5178 gNumWaitingThreads
++;
5181 IOUnlock( gJobsLock
);
5186 if (gIOKitDebug
& kIOLogConfig
) {
5187 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
5189 _IOConfigThread::configThread(gNumConfigThreads
- 1);
5192 semaphore_signal( gJobsSemaphore
);
5195 struct IOServiceMatchContext
{
5196 OSDictionary
* table
;
5205 IOService::instanceMatch(const OSObject
* entry
, void * context
)
5207 IOServiceMatchContext
* ctx
= (typeof(ctx
))context
;
5208 IOService
* service
= (typeof(service
))entry
;
5209 OSDictionary
* table
= ctx
->table
;
5210 uint32_t options
= ctx
->options
;
5211 uint32_t state
= ctx
->state
;
5217 match
= ((state
== (state
& service
->__state
[0]))
5218 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
5222 ctx
->count
+= table
->getCount();
5223 match
= service
->matchInternal(table
, options
, &done
);
5230 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
)) {
5232 ctx
->result
= service
;
5234 } else if (!ctx
->result
) {
5235 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
5237 ((OSSet
*)ctx
->result
)->setObject(service
);
5242 // internal - call with gNotificationLock
5244 IOService::copyExistingServices( OSDictionary
* matching
,
5245 IOOptionBits inState
, IOOptionBits options
)
5247 OSObject
* current
= NULL
;
5249 IOService
* service
;
5258 OSSerialize
* s
= OSSerialize::withCapacity(128);
5259 matching
->serialize(s
);
5262 if ((obj
= matching
->getObject(gIOProviderClassKey
))
5264 && gIOResourcesKey
->isEqualTo(obj
)
5265 && (service
= gIOResources
)) {
5266 if ((inState
== (service
->__state
[0] & inState
))
5267 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5268 && service
->matchPassive(matching
, options
)) {
5269 if (options
& kIONotifyOnce
) {
5273 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
5277 IOServiceMatchContext ctx
;
5278 ctx
.table
= matching
;
5279 ctx
.state
= inState
;
5282 ctx
.options
= options
;
5285 if ((str
= OSDynamicCast(OSString
, obj
))) {
5286 const OSSymbol
* sym
= OSSymbol::withString(str
);
5287 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
5290 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
5294 current
= ctx
.result
;
5296 options
|= kIOServiceInternalDone
| kIOServiceClassDone
;
5297 if (current
&& (ctx
.done
!= ctx
.count
)) {
5299 source
= OSDynamicCast(OSSet
, current
);
5301 while ((service
= (IOService
*) source
->getAnyObject())) {
5302 if (service
->matchPassive(matching
, options
)) {
5303 if (options
& kIONotifyOnce
) {
5309 ((OSSet
*)current
)->setObject( service
);
5311 current
= OSSet::withObjects(
5312 (const OSObject
**) &service
, 1, 1 );
5315 source
->removeObject(service
);
5323 OSObject
* _current
= 0;
5325 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
5326 kIORegistryIterateRecursively
);
5330 while ((service
= (IOService
*) iter
->getNextObject())) {
5331 if ((inState
== (service
->__state
[0] & inState
))
5332 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5333 && service
->matchPassive(matching
, 0)) {
5334 if (options
& kIONotifyOnce
) {
5340 ((OSSet
*)_current
)->setObject( service
);
5342 _current
= OSSet::withObjects(
5343 (const OSObject
**) &service
, 1, 1 );
5347 } while (!service
&& !iter
->isValid());
5351 if (((current
!= 0) != (_current
!= 0))
5352 || (current
&& _current
&& !current
->isEqualTo(_current
))) {
5353 OSSerialize
* s1
= OSSerialize::withCapacity(128);
5354 OSSerialize
* s2
= OSSerialize::withCapacity(128);
5355 current
->serialize(s1
);
5356 _current
->serialize(s2
);
5357 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current
),
5358 IOSERVICE_OBFUSCATE(_current
), s
->text(), s1
->text(), s2
->text());
5364 _current
->release();
5371 if (current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
5372 iter
= OSCollectionIterator::withCollection((OSSet
*)current
);
5382 IOService::getMatchingServices( OSDictionary
* matching
)
5386 // is a lock even needed?
5389 iter
= (OSIterator
*) copyExistingServices( matching
,
5390 kIOServiceMatchedState
);
5398 IOService::copyMatchingService( OSDictionary
* matching
)
5400 IOService
* service
;
5402 // is a lock even needed?
5405 service
= (IOService
*) copyExistingServices( matching
,
5406 kIOServiceMatchedState
, kIONotifyOnce
);
5413 struct _IOServiceMatchingNotificationHandlerRef
{
5414 IOServiceNotificationHandler handler
;
5419 _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
5420 IOService
* newService
,
5421 IONotifier
* notifier
)
5423 return (*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
);
5426 // internal - call with gNotificationLock
5428 IOService::setNotification(
5429 const OSSymbol
* type
, OSDictionary
* matching
,
5430 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
5433 _IOServiceNotifier
* notify
= NULL
;
5440 notify
= new _IOServiceNotifier
;
5441 if (notify
&& !notify
->init()) {
5447 notify
->handler
= handler
;
5448 notify
->target
= target
;
5449 notify
->type
= type
;
5450 notify
->matching
= matching
;
5452 if (handler
== &_IOServiceMatchingNotificationHandler
) {
5453 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
5454 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
5458 notify
->priority
= priority
;
5459 notify
->state
= kIOServiceNotifyEnable
;
5460 queue_init( ¬ify
->handlerInvocations
);
5464 if (NULL
== (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
5465 set
= OSOrderedSet::withCapacity( 1,
5466 IONotifyOrdering
, NULL
);
5468 gNotifications
->setObject( type
, set
);
5472 notify
->whence
= set
;
5474 set
->setObject( notify
);
5481 // internal - call with gNotificationLock
5483 IOService::doInstallNotification(
5484 const OSSymbol
* type
, OSDictionary
* matching
,
5485 IOServiceMatchingNotificationHandler handler
,
5486 void * target
, void * ref
,
5487 SInt32 priority
, OSIterator
** existing
)
5490 IONotifier
* notify
;
5491 IOOptionBits inState
;
5497 if (type
== gIOPublishNotification
) {
5498 inState
= kIOServiceRegisteredState
;
5499 } else if (type
== gIOFirstPublishNotification
) {
5500 inState
= kIOServiceFirstPublishState
;
5501 } else if (type
== gIOMatchedNotification
) {
5502 inState
= kIOServiceMatchedState
;
5503 } else if (type
== gIOFirstMatchNotification
) {
5504 inState
= kIOServiceFirstMatchState
;
5505 } else if ((type
== gIOTerminatedNotification
) || (type
== gIOWillTerminateNotification
)) {
5511 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
5514 // get the current set
5515 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
5525 #if !defined(__LP64__)
5527 IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
5528 IOServiceNotificationHandler handler
,
5529 void * target
, void * refCon
,
5530 SInt32 priority
, OSIterator
** existing
)
5532 IONotifier
* result
;
5533 _IOServiceMatchingNotificationHandlerRef ref
;
5534 ref
.handler
= handler
;
5537 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5538 &_IOServiceMatchingNotificationHandler
,
5539 target
, &ref
, priority
, existing
);
5541 matching
->release();
5546 #endif /* !defined(__LP64__) */
5550 IOService::installNotification(
5551 const OSSymbol
* type
, OSDictionary
* matching
,
5552 IOServiceMatchingNotificationHandler handler
,
5553 void * target
, void * ref
,
5554 SInt32 priority
, OSIterator
** existing
)
5556 IONotifier
* notify
;
5560 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
5561 priority
, existing
);
5563 // in case handler remove()s
5574 IOService::addNotification(
5575 const OSSymbol
* type
, OSDictionary
* matching
,
5576 IOServiceNotificationHandler handler
,
5577 void * target
, void * refCon
,
5580 IONotifier
* result
;
5581 _IOServiceMatchingNotificationHandlerRef ref
;
5583 ref
.handler
= handler
;
5586 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
5587 target
, &ref
, priority
);
5590 matching
->release();
5597 IOService::addMatchingNotification(
5598 const OSSymbol
* type
, OSDictionary
* matching
,
5599 IOServiceMatchingNotificationHandler handler
,
5600 void * target
, void * ref
,
5603 OSIterator
* existing
= NULL
;
5605 _IOServiceNotifier
* notify
;
5608 ret
= notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5609 handler
, target
, ref
, priority
, &existing
);
5614 // send notifications for existing set
5616 while ((next
= (IOService
*) existing
->getNextObject())) {
5617 if (0 == (next
->__state
[0] & kIOServiceInactiveState
)) {
5618 next
->invokeNotifier( notify
);
5621 existing
->release();
5625 bool removed
= (NULL
== notify
->whence
);
5628 ret
= gIOServiceNullNotifier
;
5636 IOServiceMatchingNotificationHandlerToBlock( void * target __unused
, void * refCon
,
5637 IOService
* newService
,
5638 IONotifier
* notifier
)
5640 return ((IOServiceMatchingNotificationHandlerBlock
) refCon
)(newService
, notifier
);
5644 IOService::addMatchingNotification(
5645 const OSSymbol
* type
, OSDictionary
* matching
,
5647 IOServiceMatchingNotificationHandlerBlock handler
)
5649 IONotifier
* notify
;
5652 block
= Block_copy(handler
);
5657 notify
= addMatchingNotification(type
, matching
,
5658 &IOServiceMatchingNotificationHandlerToBlock
, NULL
, block
, priority
);
5661 Block_release(block
);
5669 IOService::syncNotificationHandler(
5670 void * /* target */, void * ref
,
5671 IOService
* newService
,
5672 IONotifier
* notifier
)
5675 if (!*((IOService
**) ref
)) {
5676 newService
->retain();
5677 (*(IOService
**) ref
) = newService
;
5686 IOService::waitForMatchingService( OSDictionary
* matching
,
5689 IONotifier
* notify
= NULL
;
5690 // priority doesn't help us much since we need a thread wakeup
5691 SInt32 priority
= 0;
5702 result
= (IOService
*) copyExistingServices( matching
,
5703 kIOServiceMatchedState
, kIONotifyOnce
);
5707 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
5708 &IOService::syncNotificationHandler
, (void *) NULL
,
5709 &result
, priority
);
5713 if (UINT64_MAX
!= timeout
) {
5714 AbsoluteTime deadline
;
5715 nanoseconds_to_absolutetime(timeout
, &deadline
);
5716 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
5717 SLEEPNOTIFYTO(&result
, deadline
);
5719 SLEEPNOTIFY(&result
);
5726 notify
->remove(); // dequeues
5732 IOService::waitForService( OSDictionary
* matching
,
5733 mach_timespec_t
* timeout
)
5739 timeoutNS
= timeout
->tv_sec
;
5740 timeoutNS
*= kSecondScale
;
5741 timeoutNS
+= timeout
->tv_nsec
;
5743 timeoutNS
= UINT64_MAX
;
5746 result
= waitForMatchingService(matching
, timeoutNS
);
5748 matching
->release();
5758 IOService::deliverNotification( const OSSymbol
* type
,
5759 IOOptionBits orNewState
, IOOptionBits andNewState
)
5761 panic("deliverNotification");
5765 IOService::copyNotifiers(const OSSymbol
* type
,
5766 IOOptionBits orNewState
, IOOptionBits andNewState
)
5768 _IOServiceNotifier
* notify
;
5770 OSArray
* willSend
= NULL
;
5772 lockForArbitration();
5774 if ((0 == (__state
[0] & kIOServiceInactiveState
))
5775 || (type
== gIOTerminatedNotification
)
5776 || (type
== gIOWillTerminateNotification
)) {
5779 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
5780 gNotifications
->getObject( type
));
5783 while ((notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
5784 if (matchPassive(notify
->matching
, 0)
5785 && (kIOServiceNotifyEnable
& notify
->state
)) {
5786 if (NULL
== willSend
) {
5787 willSend
= OSArray::withCapacity(8);
5790 willSend
->setObject( notify
);
5796 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
5800 unlockForArbitration();
5806 IOService::getState( void ) const
5812 * Helpers to make matching objects for simple cases
5816 IOService::serviceMatching( const OSString
* name
,
5817 OSDictionary
* table
)
5819 const OSString
* str
;
5821 str
= OSSymbol::withString(name
);
5827 table
= OSDictionary::withCapacity( 2 );
5830 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
5838 IOService::serviceMatching( const char * name
,
5839 OSDictionary
* table
)
5841 const OSString
* str
;
5843 str
= OSSymbol::withCString( name
);
5848 table
= serviceMatching( str
, table
);
5854 IOService::nameMatching( const OSString
* name
,
5855 OSDictionary
* table
)
5858 table
= OSDictionary::withCapacity( 2 );
5861 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
5868 IOService::nameMatching( const char * name
,
5869 OSDictionary
* table
)
5871 const OSString
* str
;
5873 str
= OSSymbol::withCString( name
);
5878 table
= nameMatching( str
, table
);
5884 IOService::resourceMatching( const OSString
* str
,
5885 OSDictionary
* table
)
5887 table
= serviceMatching( gIOResourcesKey
, table
);
5889 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
5896 IOService::resourceMatching( const char * name
,
5897 OSDictionary
* table
)
5899 const OSSymbol
* str
;
5901 str
= OSSymbol::withCString( name
);
5906 table
= resourceMatching( str
, table
);
5913 IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
5914 OSDictionary
* table
)
5916 OSDictionary
* properties
;
5918 properties
= OSDictionary::withCapacity( 2 );
5922 properties
->setObject( key
, value
);
5925 table
= OSDictionary::withCapacity( 2 );
5928 table
->setObject( gIOPropertyMatchKey
, properties
);
5931 properties
->release();
5937 IOService::registryEntryIDMatching( uint64_t entryID
,
5938 OSDictionary
* table
)
5942 num
= OSNumber::withNumber( entryID
, 64 );
5948 table
= OSDictionary::withCapacity( 2 );
5951 table
->setObject( gIORegistryEntryIDKey
, num
);
5963 * _IOServiceNotifier
5966 // wait for all threads, other than the current one,
5967 // to exit the handler
5970 _IOServiceNotifier::wait()
5972 _IOServiceNotifierInvocation
* next
;
5977 queue_iterate( &handlerInvocations
, next
,
5978 _IOServiceNotifierInvocation
*, link
) {
5979 if (next
->thread
!= current_thread()) {
5985 state
|= kIOServiceNotifyWaiter
;
5992 _IOServiceNotifier::free()
5994 assert( queue_empty( &handlerInvocations
));
5996 if (handler
== &IOServiceMatchingNotificationHandlerToBlock
) {
6004 _IOServiceNotifier::remove()
6009 whence
->removeObject((OSObject
*) this );
6013 matching
->release();
6017 state
&= ~kIOServiceNotifyEnable
;
6027 _IOServiceNotifier::disable()
6033 ret
= (0 != (kIOServiceNotifyEnable
& state
));
6034 state
&= ~kIOServiceNotifyEnable
;
6045 _IOServiceNotifier::enable( bool was
)
6049 state
|= kIOServiceNotifyEnable
;
6051 state
&= ~kIOServiceNotifyEnable
;
6058 * _IOServiceNullNotifier
6062 _IOServiceNullNotifier::taggedRetain(const void *tag
) const
6066 _IOServiceNullNotifier::taggedRelease(const void *tag
, const int when
) const
6070 _IOServiceNullNotifier::free()
6074 _IOServiceNullNotifier::wait()
6078 _IOServiceNullNotifier::remove()
6082 _IOServiceNullNotifier::enable(bool was
)
6086 _IOServiceNullNotifier::disable()
6096 IOResources::resources( void )
6100 inst
= new IOResources
;
6101 if (inst
&& !inst
->init()) {
6110 IOResources::init( OSDictionary
* dictionary
)
6112 // Do super init first
6113 if (!IOService::init()) {
6117 // Allow PAL layer to publish a value
6118 const char *property_name
;
6121 pal_get_resource_property( &property_name
, &property_value
);
6123 if (property_name
) {
6125 const OSSymbol
* sym
;
6127 if ((num
= OSNumber::withNumber(property_value
, 32)) != NULL
) {
6128 if ((sym
= OSSymbol::withCString( property_name
)) != NULL
) {
6129 this->setProperty( sym
, num
);
6140 IOResources::newUserClient(task_t owningTask
, void * securityID
,
6141 UInt32 type
, OSDictionary
* properties
,
6142 IOUserClient
** handler
)
6144 return kIOReturnUnsupported
;
6148 IOResources::getWorkLoop() const
6150 // If we are the resource root
6151 // then use the platform's workloop
6152 if (this == (IOResources
*) gIOResources
) {
6153 return getPlatform()->getWorkLoop();
6155 return IOService::getWorkLoop();
6160 IOResourcesMatchPropertyTable(IOService
* resources
, OSDictionary
* table
)
6170 prop
= table
->getObject( gIOResourceMatchKey
);
6171 str
= OSDynamicCast( OSString
, prop
);
6173 ok
= (NULL
!= resources
->getProperty( str
));
6174 } else if ((set
= OSDynamicCast( OSSet
, prop
))) {
6175 iter
= OSCollectionIterator::withCollection( set
);
6176 ok
= (iter
!= NULL
);
6177 while (ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6178 ok
= (NULL
!= resources
->getProperty( str
));
6184 } else if ((prop
= table
->getObject(gIOResourceMatchedKey
))) {
6185 obj
= resources
->copyProperty(gIOResourceMatchedKey
);
6186 keys
= OSDynamicCast(OSArray
, obj
);
6189 // assuming OSSymbol
6190 ok
= ((-1U) != keys
->getNextIndexOfObject(prop
, 0));
6192 OSSafeReleaseNULL(obj
);
6199 IOResources::matchPropertyTable( OSDictionary
* table
)
6201 return IOResourcesMatchPropertyTable(this, table
);
6209 IOUserResources::resources( void )
6211 IOUserResources
* inst
;
6213 inst
= OSTypeAlloc(IOUserResources
);
6214 if (inst
&& !inst
->init()) {
6223 IOUserResources::init( OSDictionary
* dictionary
)
6225 // Do super init first
6226 if (!IOService::init()) {
6233 IOUserResources::newUserClient(task_t owningTask
, void * securityID
,
6234 UInt32 type
, OSDictionary
* properties
,
6235 IOUserClient
** handler
)
6237 return kIOReturnUnsupported
;
6241 IOUserResources::getWorkLoop() const
6243 return getPlatform()->getWorkLoop();
6247 IOUserResources::matchPropertyTable( OSDictionary
* table
)
6249 return IOResourcesMatchPropertyTable(this, table
);
6255 IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
6257 IOService::updateConsoleUsers(NULL
, 0);
6261 IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
)
6263 IORegistryEntry
* regEntry
;
6264 OSObject
* locked
= kOSBooleanFalse
;
6267 OSDictionary
* user
;
6268 static IOMessage sSystemPower
;
6269 clock_sec_t now
= 0;
6270 clock_usec_t microsecs
;
6272 regEntry
= IORegistryEntry::getRegistryRoot();
6274 if (!gIOChosenEntry
) {
6275 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
6278 IOLockLock(gIOConsoleUsersLock
);
6280 if (systemMessage
) {
6281 sSystemPower
= systemMessage
;
6283 if (kIOMessageSystemHasPoweredOn
== systemMessage
) {
6284 uint32_t lockState
= IOHibernateWasScreenLocked();
6285 switch (lockState
) {
6288 case kIOScreenLockLocked
:
6289 case kIOScreenLockFileVaultDialog
:
6290 gIOConsoleBooterLockState
= kOSBooleanTrue
;
6292 case kIOScreenLockNoLock
:
6293 gIOConsoleBooterLockState
= NULL
;
6295 case kIOScreenLockUnlocked
:
6297 gIOConsoleBooterLockState
= kOSBooleanFalse
;
6301 #endif /* HIBERNATION */
6305 OSNumber
* num
= NULL
;
6306 bool loginLocked
= true;
6308 gIOConsoleLoggedIn
= false;
6310 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
6312 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
6313 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
6315 loginLocked
&= (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionScreenIsLockedKey
));
6317 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
6322 gIOConsoleBooterLockState
= NULL
;
6324 IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
6325 (num
!= NULL
), gIOConsoleLockTime
, (num
? num
->unsigned32BitValue() : 0),
6326 gIOConsoleLoggedIn
, loginLocked
);
6327 #endif /* HIBERNATION */
6328 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
6331 if (!gIOConsoleLoggedIn
6332 || (kIOMessageSystemWillSleep
== sSystemPower
)
6333 || (kIOMessageSystemPagingOff
== sSystemPower
)) {
6334 locked
= kOSBooleanTrue
;
6337 else if (gIOConsoleBooterLockState
) {
6338 locked
= gIOConsoleBooterLockState
;
6340 #endif /* HIBERNATION */
6341 else if (gIOConsoleLockTime
) {
6342 clock_get_calendar_microtime(&now
, µsecs
);
6343 if (gIOConsoleLockTime
> now
) {
6344 AbsoluteTime deadline
;
6345 clock_interval_to_deadline(gIOConsoleLockTime
- now
, kSecondScale
, &deadline
);
6346 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
6348 locked
= kOSBooleanTrue
;
6352 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
6354 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
6356 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
6358 OSIncrementAtomic( &gIOConsoleUsersSeed
);
6362 if (gIOChosenEntry
) {
6363 if (locked
== kOSBooleanTrue
) {
6364 gIOScreenLockState
= kIOScreenLockLocked
;
6365 } else if (gIOConsoleLockTime
) {
6366 gIOScreenLockState
= kIOScreenLockUnlocked
;
6368 gIOScreenLockState
= kIOScreenLockNoLock
;
6370 gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &gIOScreenLockState
, sizeof(gIOScreenLockState
));
6372 IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
6373 gIOScreenLockState
, gIOHibernateState
, (gIOConsoleBooterLockState
!= NULL
), now
, systemMessage
);
6375 #endif /* HIBERNATION */
6377 IOLockUnlock(gIOConsoleUsersLock
);
6380 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
6382 MessageClientsContext context
;
6384 context
.service
= getServiceRoot();
6385 context
.type
= kIOMessageConsoleSecurityChange
;
6386 context
.argument
= (void *) regEntry
;
6387 context
.argSize
= 0;
6389 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
6390 &messageClientsApplier
, &context
);
6395 IOResources::setProperties( OSObject
* properties
)
6398 const OSSymbol
* key
;
6399 OSDictionary
* dict
;
6400 OSCollectionIterator
* iter
;
6402 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
6403 if (kIOReturnSuccess
!= err
) {
6407 dict
= OSDynamicCast(OSDictionary
, properties
);
6409 return kIOReturnBadArgument
;
6412 iter
= OSCollectionIterator::withCollection( dict
);
6414 return kIOReturnBadArgument
;
6417 while ((key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
6418 if (gIOConsoleUsersKey
== key
) {
6420 OSArray
* consoleUsers
;
6421 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
6422 if (!consoleUsers
) {
6425 IOService::updateConsoleUsers(consoleUsers
, 0);
6429 publishResource( key
, dict
->getObject(key
));
6434 return kIOReturnSuccess
;
6438 * Helpers for matching dictionaries.
6439 * Keys existing in matching are checked in properties.
6440 * Keys may be a string or OSCollection of IOStrings
6444 IOService::compareProperty( OSDictionary
* matching
,
6451 value
= matching
->getObject( key
);
6453 prop
= copyProperty(key
);
6454 ok
= value
->isEqualTo(prop
);
6467 IOService::compareProperty( OSDictionary
* matching
,
6468 const OSString
* key
)
6474 value
= matching
->getObject( key
);
6476 prop
= copyProperty(key
);
6477 ok
= value
->isEqualTo(prop
);
6489 IOService::compareProperties( OSDictionary
* matching
,
6490 OSCollection
* keys
)
6492 OSCollectionIterator
* iter
;
6493 const OSString
* key
;
6496 if (!matching
|| !keys
) {
6500 iter
= OSCollectionIterator::withCollection( keys
);
6503 while (ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6504 ok
= compareProperty( matching
, key
);
6509 keys
->release(); // !! consume a ref !!
6514 /* Helper to add a location matching dict to the table */
6517 IOService::addLocation( OSDictionary
* table
)
6519 OSDictionary
* dict
;
6525 dict
= OSDictionary::withCapacity( 1 );
6527 bool ok
= table
->setObject( gIOLocationMatchKey
, dict
);
6538 * Go looking for a provider to match a location dict.
6542 IOService::matchLocation( IOService
* /* client */ )
6546 parent
= getProvider();
6549 parent
= parent
->matchLocation( this );
6556 IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
6561 IORegistryEntry
* entry
;
6564 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
6569 count
= table
->getCount();
6572 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
6575 match
= ((kIOServiceClassDone
& options
) || (NULL
!= metaCast(str
)));
6577 match
= (0 != metaCast( str
));
6578 if ((kIOServiceClassDone
& options
) && !match
) {
6582 if ((!match
) || (done
== count
)) {
6587 obj
= table
->getObject( gIONameMatchKey
);
6590 match
= compareNames( obj
, changesOK
? &matched
: NULL
);
6594 if (changesOK
&& matched
) {
6595 // leave a hint as to which name matched
6596 table
->setObject( gIONameMatchedKey
, matched
);
6599 if (done
== count
) {
6604 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
6606 const OSSymbol
* sym
;
6609 sym
= copyLocation();
6611 match
= sym
->isEqualTo( str
);
6614 if ((!match
) || (done
== count
)) {
6619 obj
= table
->getObject( gIOPropertyMatchKey
);
6621 OSDictionary
* dict
;
6622 OSDictionary
* nextDict
;
6626 dict
= dictionaryWithProperties();
6628 nextDict
= OSDynamicCast( OSDictionary
, obj
);
6632 iter
= OSCollectionIterator::withCollection(
6633 OSDynamicCast(OSCollection
, obj
));
6637 || (iter
&& (NULL
!= (nextDict
= OSDynamicCast(OSDictionary
,
6638 iter
->getNextObject()))))) {
6639 match
= dict
->isEqualTo( nextDict
, nextDict
);
6650 if ((!match
) || (done
== count
)) {
6655 obj
= table
->getObject( gIOPropertyExistsMatchKey
);
6657 OSDictionary
* dict
;
6662 dict
= dictionaryWithProperties();
6664 nextKey
= OSDynamicCast( OSString
, obj
);
6668 iter
= OSCollectionIterator::withCollection(
6669 OSDynamicCast(OSCollection
, obj
));
6673 || (iter
&& (NULL
!= (nextKey
= OSDynamicCast(OSString
,
6674 iter
->getNextObject()))))) {
6675 match
= (NULL
!= dict
->getObject(nextKey
));
6686 if ((!match
) || (done
== count
)) {
6691 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
6694 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy());
6695 match
= (this == entry
);
6699 if ((!match
) || (done
== count
)) {
6704 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
6707 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
6708 if ((!match
) || (done
== count
)) {
6713 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
6716 IOService
* service
= NULL
;
6717 UInt32 serviceCount
= 0;
6720 iter
= getClientIterator();
6722 while ((service
= (IOService
*) iter
->getNextObject())) {
6723 if (kIOServiceInactiveState
& service
->__state
[0]) {
6726 if (NULL
== service
->getProperty( gIOMatchCategoryKey
)) {
6733 match
= (serviceCount
== num
->unsigned32BitValue());
6734 if ((!match
) || (done
== count
)) {
6739 #define propMatch(key) \
6740 obj = table->getObject(key); \
6745 prop = copyProperty(key); \
6746 match = obj->isEqualTo(prop); \
6747 if (prop) prop->release(); \
6748 if ((!match) || (done == count)) break; \
6750 propMatch(gIOBSDNameKey
)
6751 propMatch(gIOBSDMajorKey
)
6752 propMatch(gIOBSDMinorKey
)
6753 propMatch(gIOBSDUnitKey
)
6764 IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
6766 return matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0);
6770 IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
6773 OSDictionary
* nextTable
;
6777 bool matchParent
= false;
6783 #if !CONFIG_EMBEDDED
6784 OSArray
* aliasServiceRegIds
= NULL
;
6785 IOService
* foundAlternateService
= NULL
;
6789 OSDictionary
* root
= table
;
6795 count
= table
->getCount();
6796 if (!(kIOServiceInternalDone
& options
)) {
6797 match
= where
->matchInternal(table
, options
, &done
);
6798 // don't call family if we've done all the entries in the table
6799 if ((!match
) || (done
== count
)) {
6804 // pass in score from property table
6805 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
6807 // do family specific matching
6808 match
= where
->matchPropertyTable( table
, &score
);
6812 if (kIOLogMatch
& getDebugFlags( table
)) {
6813 LOG("%s: family specific matching fails\n", where
->getName());
6819 if (kIOServiceChangesOK
& options
) {
6821 newPri
= OSNumber::withNumber( score
, 32 );
6823 table
->setObject( gIOProbeScoreKey
, newPri
);
6829 matchParent
= false;
6831 nextTable
= OSDynamicCast(OSDictionary
,
6832 table
->getObject( gIOParentMatchKey
));
6834 // look for a matching entry anywhere up to root
6841 table
= OSDynamicCast(OSDictionary
,
6842 table
->getObject( gIOLocationMatchKey
));
6844 // look for a matching entry at matchLocation()
6846 where
= where
->getProvider();
6847 if (where
&& (where
= where
->matchLocation(where
))) {
6854 if (match
== true) {
6858 if (matchParent
== true) {
6859 #if !CONFIG_EMBEDDED
6860 // check if service has an alias to search its other "parents" if a parent match isn't found
6861 OSObject
* prop
= where
->copyProperty(gIOServiceLegacyMatchingRegistryIDKey
);
6862 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, prop
);
6863 if (alternateRegistryID
!= NULL
) {
6864 if (aliasServiceRegIds
== NULL
) {
6865 aliasServiceRegIds
= OSArray::withCapacity(sizeof(alternateRegistryID
));
6867 aliasServiceRegIds
->setObject(alternateRegistryID
);
6869 OSSafeReleaseNULL(prop
);
6875 where
= where
->getProvider();
6876 #if !CONFIG_EMBEDDED
6877 if (where
== NULL
) {
6878 // there were no matching parent services, check to see if there are aliased services that have a matching parent
6879 if (aliasServiceRegIds
!= NULL
) {
6880 unsigned int numAliasedServices
= aliasServiceRegIds
->getCount();
6881 if (numAliasedServices
!= 0) {
6882 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, aliasServiceRegIds
->getObject(numAliasedServices
- 1));
6883 if (alternateRegistryID
!= NULL
) {
6884 OSDictionary
* alternateMatchingDict
= IOService::registryEntryIDMatching(alternateRegistryID
->unsigned64BitValue());
6885 aliasServiceRegIds
->removeObject(numAliasedServices
- 1);
6886 if (alternateMatchingDict
!= NULL
) {
6887 OSSafeReleaseNULL(foundAlternateService
);
6888 foundAlternateService
= IOService::copyMatchingService(alternateMatchingDict
);
6889 alternateMatchingDict
->release();
6890 if (foundAlternateService
!= NULL
) {
6891 where
= foundAlternateService
;
6899 }while (where
!= NULL
);
6901 #if !CONFIG_EMBEDDED
6902 OSSafeReleaseNULL(foundAlternateService
);
6903 OSSafeReleaseNULL(aliasServiceRegIds
);
6907 if (where
!= this) {
6908 OSSerialize
* s
= OSSerialize::withCapacity(128);
6910 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
6920 IOService::newUserClient( task_t owningTask
, void * securityID
,
6921 UInt32 type
, OSDictionary
* properties
,
6922 IOUserClient
** handler
)
6924 const OSSymbol
*userClientClass
= NULL
;
6925 IOUserClient
*client
;
6929 if (reserved
&& reserved
->uvars
&& reserved
->uvars
->userServer
) {
6930 return reserved
->uvars
->userServer
->serviceNewUserClient(this, owningTask
, securityID
, type
, properties
, handler
);
6933 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
)) {
6934 return kIOReturnSuccess
;
6937 // First try my own properties for a user client class name
6938 prop
= copyProperty(gIOUserClientClassKey
);
6940 if (OSDynamicCast(OSSymbol
, prop
)) {
6941 userClientClass
= (const OSSymbol
*) prop
;
6942 } else if (OSDynamicCast(OSString
, prop
)) {
6943 userClientClass
= OSSymbol::withString((OSString
*) prop
);
6944 if (userClientClass
) {
6945 setProperty(gIOUserClientClassKey
,
6946 (OSObject
*) userClientClass
);
6951 // Didn't find one so lets just bomb out now without further ado.
6952 if (!userClientClass
) {
6953 OSSafeReleaseNULL(prop
);
6954 return kIOReturnUnsupported
;
6957 // This reference is consumed by the IOServiceOpen call
6958 temp
= OSMetaClass::allocClassWithName(userClientClass
);
6959 OSSafeReleaseNULL(prop
);
6961 return kIOReturnNoMemory
;
6964 if (OSDynamicCast(IOUserClient
, temp
)) {
6965 client
= (IOUserClient
*) temp
;
6968 return kIOReturnUnsupported
;
6971 if (!client
->initWithTask(owningTask
, securityID
, type
, properties
)) {
6973 return kIOReturnBadArgument
;
6976 if (!client
->attach(this)) {
6978 return kIOReturnUnsupported
;
6981 if (!client
->start(this)) {
6982 client
->detach(this);
6984 return kIOReturnUnsupported
;
6988 return kIOReturnSuccess
;
6992 IOService::newUserClient( task_t owningTask
, void * securityID
,
6993 UInt32 type
, IOUserClient
** handler
)
6995 return kIOReturnUnsupported
;
6999 IOService::requestProbe( IOOptionBits options
)
7001 return kIOReturnUnsupported
;
7005 * Convert an IOReturn to text. Subclasses which add additional
7006 * IOReturn's should override this method and call
7007 * super::stringFromReturn if the desired value is not found.
7011 IOService::stringFromReturn( IOReturn rtn
)
7013 static const IONamedValue IOReturn_values
[] = {
7014 {kIOReturnSuccess
, "success" },
7015 {kIOReturnError
, "general error" },
7016 {kIOReturnNoMemory
, "memory allocation error" },
7017 {kIOReturnNoResources
, "resource shortage" },
7018 {kIOReturnIPCError
, "Mach IPC failure" },
7019 {kIOReturnNoDevice
, "no such device" },
7020 {kIOReturnNotPrivileged
, "privilege violation" },
7021 {kIOReturnBadArgument
, "invalid argument" },
7022 {kIOReturnLockedRead
, "device is read locked" },
7023 {kIOReturnLockedWrite
, "device is write locked" },
7024 {kIOReturnExclusiveAccess
, "device is exclusive access" },
7025 {kIOReturnBadMessageID
, "bad IPC message ID" },
7026 {kIOReturnUnsupported
, "unsupported function" },
7027 {kIOReturnVMError
, "virtual memory error" },
7028 {kIOReturnInternalError
, "internal driver error" },
7029 {kIOReturnIOError
, "I/O error" },
7030 {kIOReturnCannotLock
, "cannot acquire lock" },
7031 {kIOReturnNotOpen
, "device is not open" },
7032 {kIOReturnNotReadable
, "device is not readable" },
7033 {kIOReturnNotWritable
, "device is not writeable" },
7034 {kIOReturnNotAligned
, "alignment error" },
7035 {kIOReturnBadMedia
, "media error" },
7036 {kIOReturnStillOpen
, "device is still open" },
7037 {kIOReturnRLDError
, "rld failure" },
7038 {kIOReturnDMAError
, "DMA failure" },
7039 {kIOReturnBusy
, "device is busy" },
7040 {kIOReturnTimeout
, "I/O timeout" },
7041 {kIOReturnOffline
, "device is offline" },
7042 {kIOReturnNotReady
, "device is not ready" },
7043 {kIOReturnNotAttached
, "device/channel is not attached" },
7044 {kIOReturnNoChannels
, "no DMA channels available" },
7045 {kIOReturnNoSpace
, "no space for data" },
7046 {kIOReturnPortExists
, "device port already exists" },
7047 {kIOReturnCannotWire
, "cannot wire physical memory" },
7048 {kIOReturnNoInterrupt
, "no interrupt attached" },
7049 {kIOReturnNoFrames
, "no DMA frames enqueued" },
7050 {kIOReturnMessageTooLarge
, "message is too large" },
7051 {kIOReturnNotPermitted
, "operation is not permitted" },
7052 {kIOReturnNoPower
, "device is without power" },
7053 {kIOReturnNoMedia
, "media is not present" },
7054 {kIOReturnUnformattedMedia
, "media is not formatted" },
7055 {kIOReturnUnsupportedMode
, "unsupported mode" },
7056 {kIOReturnUnderrun
, "data underrun" },
7057 {kIOReturnOverrun
, "data overrun" },
7058 {kIOReturnDeviceError
, "device error" },
7059 {kIOReturnNoCompletion
, "no completion routine" },
7060 {kIOReturnAborted
, "operation was aborted" },
7061 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
7062 {kIOReturnNotResponding
, "device is not responding" },
7063 {kIOReturnInvalid
, "unanticipated driver error" },
7067 return IOFindNameForValue(rtn
, IOReturn_values
);
7071 * Convert an IOReturn to an errno.
7074 IOService::errnoFromReturn( IOReturn rtn
)
7076 if (unix_err(err_get_code(rtn
)) == rtn
) {
7077 return err_get_code(rtn
);
7082 case kIOReturnSuccess
:
7084 case kIOReturnNoMemory
:
7086 case kIOReturnNoDevice
:
7088 case kIOReturnVMError
:
7090 case kIOReturnNotPermitted
:
7092 case kIOReturnNotPrivileged
:
7094 case kIOReturnIOError
:
7096 case kIOReturnNotWritable
:
7098 case kIOReturnBadArgument
:
7100 case kIOReturnUnsupported
:
7104 case kIOReturnNoPower
:
7106 case kIOReturnDeviceError
:
7108 case kIOReturnTimeout
:
7110 case kIOReturnMessageTooLarge
:
7112 case kIOReturnNoSpace
:
7114 case kIOReturnCannotLock
:
7118 case kIOReturnBadMessageID
:
7119 case kIOReturnNoCompletion
:
7120 case kIOReturnNotAligned
:
7122 case kIOReturnNotReady
:
7124 case kIOReturnRLDError
:
7126 case kIOReturnPortExists
:
7127 case kIOReturnStillOpen
:
7129 case kIOReturnExclusiveAccess
:
7130 case kIOReturnLockedRead
:
7131 case kIOReturnLockedWrite
:
7132 case kIOReturnNotOpen
:
7133 case kIOReturnNotReadable
:
7135 case kIOReturnCannotWire
:
7136 case kIOReturnNoResources
:
7138 case kIOReturnAborted
:
7139 case kIOReturnOffline
:
7140 case kIOReturnNotResponding
:
7142 case kIOReturnBadMedia
:
7143 case kIOReturnNoMedia
:
7144 case kIOReturnNotAttached
:
7145 case kIOReturnUnformattedMedia
:
7146 return ENXIO
; // (media error)
7147 case kIOReturnDMAError
:
7148 case kIOReturnOverrun
:
7149 case kIOReturnUnderrun
:
7150 return EIO
; // (transfer error)
7151 case kIOReturnNoBandwidth
:
7152 case kIOReturnNoChannels
:
7153 case kIOReturnNoFrames
:
7154 case kIOReturnNoInterrupt
:
7155 return EIO
; // (hardware error)
7156 case kIOReturnError
:
7157 case kIOReturnInternalError
:
7158 case kIOReturnInvalid
:
7159 return EIO
; // (generic error)
7160 case kIOReturnIPCError
:
7161 return EIO
; // (ipc error)
7163 return EIO
; // (all other errors)
7168 IOService::message( UInt32 type
, IOService
* provider
,
7172 * Generic entry point for calls from the provider. A return value of
7173 * kIOReturnSuccess indicates that the message was received, and where
7174 * applicable, that it was successful.
7177 return kIOReturnUnsupported
;
7185 IOService::getDeviceMemoryCount( void )
7190 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7192 count
= array
->getCount();
7201 IOService::getDeviceMemoryWithIndex( unsigned int index
)
7204 IODeviceMemory
* range
;
7206 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7208 range
= (IODeviceMemory
*) array
->getObject( index
);
7217 IOService::mapDeviceMemoryWithIndex( unsigned int index
,
7218 IOOptionBits options
)
7220 IODeviceMemory
* range
;
7223 range
= getDeviceMemoryWithIndex( index
);
7225 map
= range
->map( options
);
7234 IOService::getDeviceMemory( void )
7236 return OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7241 IOService::setDeviceMemory( OSArray
* array
)
7243 setProperty( gIODeviceMemoryKey
, array
);
7247 * For machines where the transfers on an I/O bus can stall because
7248 * the CPU is in an idle mode, These APIs allow a driver to specify
7249 * the maximum bus stall that they can handle. 0 indicates no limit.
7253 setCPUSnoopDelay(UInt32 __unused ns
)
7255 #if defined(__i386__) || defined(__x86_64__)
7256 ml_set_maxsnoop(ns
);
7257 #endif /* defined(__i386__) || defined(__x86_64__) */
7264 #if defined(__i386__) || defined(__x86_64__)
7265 return ml_get_maxsnoop();
7268 #endif /* defined(__i386__) || defined(__x86_64__) */
7271 #if defined(__i386__) || defined(__x86_64__)
7273 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
7275 static const UInt kNoReplace
= -1U; // Must be an illegal index
7276 UInt replace
= kNoReplace
;
7277 bool setCpuDelay
= false;
7279 IORecursiveLockLock(sCpuDelayLock
);
7281 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7282 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7283 IOService
* holder
= NULL
;
7286 const CpuDelayEntry ne
= {service
, ns
, delayType
};
7288 // Set maximum delay.
7289 for (UInt i
= 0; i
< count
; i
++) {
7290 IOService
*thisService
= entries
[i
].fService
;
7291 bool sameType
= (delayType
== entries
[i
].fDelayType
);
7292 if ((service
== thisService
) && sameType
) {
7294 } else if (!thisService
) {
7295 if (kNoReplace
== replace
) {
7298 } else if (sameType
) {
7299 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
7302 holder
= thisService
;
7308 if (kNoReplace
== replace
) {
7309 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
7311 entries
[replace
] = ne
;
7314 ns
= -1U; // Set to max unsigned, i.e. no restriction
7316 for (UInt i
= 0; i
< count
; i
++) {
7317 // Clear a maximum delay.
7318 IOService
*thisService
= entries
[i
].fService
;
7319 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
7320 UInt32 thisMax
= entries
[i
].fMaxDelay
;
7321 if (service
== thisService
) {
7323 } else if (thisMax
< ns
) {
7325 holder
= thisService
;
7330 // Check if entry found
7331 if (kNoReplace
!= replace
) {
7332 entries
[replace
].fService
= NULL
; // Null the entry
7338 if (holder
&& debug_boot_arg
) {
7339 strlcpy(sCPULatencyHolderName
[delayType
], holder
->getName(), sizeof(sCPULatencyHolderName
[delayType
]));
7342 // Must be safe to call from locked context
7343 if (delayType
== kCpuDelayBusStall
) {
7344 ml_set_maxbusdelay(ns
);
7345 } else if (delayType
== kCpuDelayInterrupt
) {
7346 ml_set_maxintdelay(ns
);
7348 sCPULatencyHolder
[delayType
]->setValue(holder
? holder
->getRegistryEntryID() : 0);
7349 sCPULatencySet
[delayType
]->setValue(ns
);
7351 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
7354 for (unsigned int idx
= 0;
7355 (target
= (IOService
*) handlers
->getObject(idx
));
7357 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7358 (void *) (uintptr_t) ns
, holder
,
7364 IORecursiveLockUnlock(sCpuDelayLock
);
7368 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
7370 IOReturn result
= kIOReturnNotFound
;
7374 IORecursiveLockLock(sCpuDelayLock
);
7377 if (enable
&& !sCpuLatencyHandlers
[delayType
]) {
7378 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
7380 array
= sCpuLatencyHandlers
[delayType
];
7384 idx
= array
->getNextIndexOfObject(target
, 0);
7387 array
->removeObject(idx
);
7388 result
= kIOReturnSuccess
;
7392 result
= kIOReturnExclusiveAccess
;
7395 array
->setObject(target
);
7397 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7398 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7399 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
7400 IOService
* holder
= NULL
;
7402 for (UInt i
= 0; i
< count
; i
++) {
7403 if (entries
[i
].fService
7404 && (delayType
== entries
[i
].fDelayType
)
7405 && (entries
[i
].fMaxDelay
< ns
)) {
7406 ns
= entries
[i
].fMaxDelay
;
7407 holder
= entries
[i
].fService
;
7410 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7411 (void *) (uintptr_t) ns
, holder
,
7413 result
= kIOReturnSuccess
;
7417 IORecursiveLockUnlock(sCpuDelayLock
);
7422 #endif /* defined(__i386__) || defined(__x86_64__) */
7426 requireMaxBusStall(UInt32 __unused ns
)
7428 #if defined(__i386__) || defined(__x86_64__)
7429 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
7435 requireMaxInterruptDelay(uint32_t __unused ns
)
7437 #if defined(__i386__) || defined(__x86_64__)
7438 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
7447 IOService::resolveInterrupt(IOService
*nub
, int source
)
7449 IOInterruptController
*interruptController
;
7452 OSSymbol
*interruptControllerName
;
7454 IOInterruptSource
*interruptSources
;
7456 // Get the parents list from the nub.
7457 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
7458 if (array
== NULL
) {
7459 return kIOReturnNoResources
;
7462 // Allocate space for the IOInterruptSources if needed... then return early.
7463 if (nub
->_interruptSources
== NULL
) {
7464 numSources
= array
->getCount();
7465 interruptSources
= (IOInterruptSource
*)IOMalloc(
7466 numSources
* sizeofAllIOInterruptSource
);
7467 if (interruptSources
== NULL
) {
7468 return kIOReturnNoMemory
;
7471 bzero(interruptSources
, numSources
* sizeofAllIOInterruptSource
);
7473 nub
->_numInterruptSources
= numSources
;
7474 nub
->_interruptSources
= interruptSources
;
7475 return kIOReturnSuccess
;
7478 interruptControllerName
= OSDynamicCast(OSSymbol
, array
->getObject(source
));
7479 if (interruptControllerName
== NULL
) {
7480 return kIOReturnNoResources
;
7483 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
7484 if (interruptController
== NULL
) {
7485 return kIOReturnNoResources
;
7488 // Get the interrupt numbers from the nub.
7489 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
7490 if (array
== NULL
) {
7491 return kIOReturnNoResources
;
7493 data
= OSDynamicCast(OSData
, array
->getObject(source
));
7495 return kIOReturnNoResources
;
7498 // Set the interruptController and interruptSource in the nub's table.
7499 interruptSources
= nub
->_interruptSources
;
7500 interruptSources
[source
].interruptController
= interruptController
;
7501 interruptSources
[source
].vectorData
= data
;
7503 return kIOReturnSuccess
;
7507 IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
7511 /* Make sure the _interruptSources are set */
7512 if (_interruptSources
== NULL
) {
7513 ret
= resolveInterrupt(this, source
);
7514 if (ret
!= kIOReturnSuccess
) {
7519 /* Make sure the local source number is valid */
7520 if ((source
< 0) || (source
>= _numInterruptSources
)) {
7521 return kIOReturnNoInterrupt
;
7524 /* Look up the contoller for the local source */
7525 *interruptController
= _interruptSources
[source
].interruptController
;
7527 if (*interruptController
== NULL
) {
7529 return kIOReturnNoInterrupt
;
7532 /* Try to resolve the interrupt */
7533 ret
= resolveInterrupt(this, source
);
7534 if (ret
!= kIOReturnSuccess
) {
7538 *interruptController
= _interruptSources
[source
].interruptController
;
7541 return kIOReturnSuccess
;
7545 IOService::registerInterrupt(int source
, OSObject
*target
,
7546 IOInterruptAction handler
,
7549 IOInterruptController
*interruptController
;
7552 ret
= lookupInterrupt(source
, true, &interruptController
);
7553 if (ret
!= kIOReturnSuccess
) {
7557 /* Register the source */
7558 return interruptController
->registerInterrupt(this, source
, target
,
7559 (IOInterruptHandler
)handler
,
7564 IOServiceInterruptActionToBlock( OSObject
* target
, void * refCon
,
7565 IOService
* nub
, int source
)
7567 ((IOInterruptActionBlock
)(refCon
))(nub
, source
);
7571 IOService::registerInterruptBlock(int source
, OSObject
*target
,
7572 IOInterruptActionBlock handler
)
7577 block
= Block_copy(handler
);
7579 return kIOReturnNoMemory
;
7582 ret
= registerInterrupt(source
, target
, &IOServiceInterruptActionToBlock
, block
);
7583 if (kIOReturnSuccess
!= ret
) {
7584 Block_release(block
);
7587 _interruptSourcesPrivate(this)[source
].vectorBlock
= block
;
7593 IOService::unregisterInterrupt(int source
)
7596 IOInterruptController
*interruptController
;
7599 ret
= lookupInterrupt(source
, false, &interruptController
);
7600 if (ret
!= kIOReturnSuccess
) {
7604 /* Unregister the source */
7605 block
= _interruptSourcesPrivate(this)[source
].vectorBlock
;
7606 ret
= interruptController
->unregisterInterrupt(this, source
);
7607 if ((kIOReturnSuccess
== ret
) && (block
= _interruptSourcesPrivate(this)[source
].vectorBlock
)) {
7608 _interruptSourcesPrivate(this)[source
].vectorBlock
= NULL
;
7609 Block_release(block
);
7616 IOService::addInterruptStatistics(IOInterruptAccountingData
* statistics
, int source
)
7618 IOReportLegend
* legend
= NULL
;
7619 IOInterruptAccountingData
* oldValue
= NULL
;
7620 IOInterruptAccountingReporter
* newArray
= NULL
;
7621 char subgroupName
[64];
7622 int newArraySize
= 0;
7626 return kIOReturnBadArgument
;
7630 * We support statistics on a maximum of 256 interrupts per nub; if a nub
7631 * has more than 256 interrupt specifiers associated with it, and tries
7632 * to register a high interrupt index with interrupt accounting, panic.
7633 * Having more than 256 interrupts associated with a single nub is
7634 * probably a sign that something fishy is going on.
7636 if (source
> IA_INDEX_MAX
) {
7637 panic("addInterruptStatistics called for an excessively large index (%d)", source
);
7641 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
7642 * leaving it as is because the likelihood of contention where we are
7643 * actually growing the array is minimal (we would realistically need
7644 * to be starting a driver for the first time, with an IOReporting
7645 * client already in place). Nonetheless, cleanup that can be done
7646 * to adhere to best practices; it'll make the code more complicated,
7649 IOLockLock(reserved
->interruptStatisticsLock
);
7652 * Lazily allocate the statistics array.
7654 if (!reserved
->interruptStatisticsArray
) {
7655 reserved
->interruptStatisticsArray
= IONew(IOInterruptAccountingReporter
, 1);
7656 assert(reserved
->interruptStatisticsArray
);
7657 reserved
->interruptStatisticsArrayCount
= 1;
7658 bzero(reserved
->interruptStatisticsArray
, sizeof(*reserved
->interruptStatisticsArray
));
7661 if (source
>= reserved
->interruptStatisticsArrayCount
) {
7663 * We're still within the range of supported indices, but we are out
7664 * of space in the current array. Do a nasty realloc (because
7665 * IORealloc isn't a thing) here. We'll double the size with each
7668 * Yes, the "next power of 2" could be more efficient; but this will
7669 * be invoked incredibly rarely. Who cares.
7671 newArraySize
= (reserved
->interruptStatisticsArrayCount
<< 1);
7673 while (newArraySize
<= source
) {
7674 newArraySize
= (newArraySize
<< 1);
7676 newArray
= IONew(IOInterruptAccountingReporter
, newArraySize
);
7681 * TODO: This even zeroes the memory it is about to overwrite.
7682 * Shameful; fix it. Not particularly high impact, however.
7684 bzero(newArray
, newArraySize
* sizeof(*newArray
));
7685 memcpy(newArray
, reserved
->interruptStatisticsArray
, reserved
->interruptStatisticsArrayCount
* sizeof(*newArray
));
7686 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
7687 reserved
->interruptStatisticsArray
= newArray
;
7688 reserved
->interruptStatisticsArrayCount
= newArraySize
;
7691 if (!reserved
->interruptStatisticsArray
[source
].reporter
) {
7693 * We don't have a reporter associated with this index yet, so we
7694 * need to create one.
7697 * TODO: Some statistics do in fact have common units (time); should this be
7698 * split into separate reporters to communicate this?
7700 reserved
->interruptStatisticsArray
[source
].reporter
= IOSimpleReporter::with(this, kIOReportCategoryPower
, kIOReportUnitNone
);
7703 * Each statistic is given an identifier based on the interrupt index (which
7704 * should be unique relative to any single nub) and the statistic involved.
7705 * We should now have a sane (small and positive) index, so start
7706 * constructing the channels for statistics.
7708 for (i
= 0; i
< IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS
; i
++) {
7710 * TODO: Currently, this does not add channels for disabled statistics.
7711 * Will this be confusing for clients? If so, we should just add the
7712 * channels; we can avoid updating the channels even if they exist.
7714 if (IA_GET_STATISTIC_ENABLED(i
)) {
7715 reserved
->interruptStatisticsArray
[source
].reporter
->addChannel(IA_GET_CHANNEL_ID(source
, i
), kInterruptAccountingStatisticNameArray
[i
]);
7720 * We now need to add the legend for this reporter to the registry.
7722 OSObject
* prop
= copyProperty(kIOReportLegendKey
);
7723 legend
= IOReportLegend::with(OSDynamicCast(OSArray
, prop
));
7724 OSSafeReleaseNULL(prop
);
7727 * Note that while we compose the subgroup name, we do not need to
7728 * manage its lifecycle (the reporter will handle this).
7730 snprintf(subgroupName
, sizeof(subgroupName
), "%s %d", getName(), source
);
7731 subgroupName
[sizeof(subgroupName
) - 1] = 0;
7732 legend
->addReporterLegend(reserved
->interruptStatisticsArray
[source
].reporter
, kInterruptAccountingGroupName
, subgroupName
);
7733 setProperty(kIOReportLegendKey
, legend
->getLegend());
7737 * TODO: Is this a good idea? Probably not; my assumption is it opts
7738 * all entities who register interrupts into public disclosure of all
7739 * IOReporting channels. Unfortunately, this appears to be as fine
7742 setProperty(kIOReportLegendPublicKey
, true);
7746 * Don't stomp existing entries. If we are about to, panic; this
7747 * probably means we failed to tear down our old interrupt source
7750 oldValue
= reserved
->interruptStatisticsArray
[source
].statistics
;
7753 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source
);
7756 reserved
->interruptStatisticsArray
[source
].statistics
= statistics
;
7759 * Inherit the reporter values for each statistic. The target may
7760 * be torn down as part of the runtime of the service (especially
7761 * for sleep/wake), so we inherit in order to avoid having values
7762 * reset for no apparent reason. Our statistics are ultimately
7763 * tied to the index and the sevice, not to an individual target,
7764 * so we should maintain them accordingly.
7766 interruptAccountingDataInheritChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
7768 IOLockUnlock(reserved
->interruptStatisticsLock
);
7770 return kIOReturnSuccess
;
7774 IOService::removeInterruptStatistics(int source
)
7776 IOInterruptAccountingData
* value
= NULL
;
7779 return kIOReturnBadArgument
;
7782 IOLockLock(reserved
->interruptStatisticsLock
);
7785 * We dynamically grow the statistics array, so an excessively
7786 * large index value has NEVER been registered. This either
7787 * means our cap on the array size is too small (unlikely), or
7788 * that we have been passed a corrupt index (this must be passed
7789 * the plain index into the interrupt specifier list).
7791 if (source
>= reserved
->interruptStatisticsArrayCount
) {
7792 panic("removeInterruptStatistics called for index %d, which was never registered", source
);
7795 assert(reserved
->interruptStatisticsArray
);
7798 * If there is no existing entry, we are most likely trying to
7799 * free an interrupt owner twice, or we have corrupted the
7802 value
= reserved
->interruptStatisticsArray
[source
].statistics
;
7805 panic("removeInterruptStatistics called for empty index %d", source
);
7809 * We update the statistics, so that any delta with the reporter
7810 * state is not lost.
7812 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
7813 reserved
->interruptStatisticsArray
[source
].statistics
= NULL
;
7814 IOLockUnlock(reserved
->interruptStatisticsLock
);
7816 return kIOReturnSuccess
;
7820 IOService::getInterruptType(int source
, int *interruptType
)
7822 IOInterruptController
*interruptController
;
7825 ret
= lookupInterrupt(source
, true, &interruptController
);
7826 if (ret
!= kIOReturnSuccess
) {
7830 /* Return the type */
7831 return interruptController
->getInterruptType(this, source
, interruptType
);
7835 IOService::enableInterrupt(int source
)
7837 IOInterruptController
*interruptController
;
7840 ret
= lookupInterrupt(source
, false, &interruptController
);
7841 if (ret
!= kIOReturnSuccess
) {
7845 /* Enable the source */
7846 return interruptController
->enableInterrupt(this, source
);
7850 IOService::disableInterrupt(int source
)
7852 IOInterruptController
*interruptController
;
7855 ret
= lookupInterrupt(source
, false, &interruptController
);
7856 if (ret
!= kIOReturnSuccess
) {
7860 /* Disable the source */
7861 return interruptController
->disableInterrupt(this, source
);
7865 IOService::causeInterrupt(int source
)
7867 IOInterruptController
*interruptController
;
7870 ret
= lookupInterrupt(source
, false, &interruptController
);
7871 if (ret
!= kIOReturnSuccess
) {
7875 /* Cause an interrupt for the source */
7876 return interruptController
->causeInterrupt(this, source
);
7880 IOService::configureReport(IOReportChannelList
*channelList
,
7881 IOReportConfigureAction action
,
7887 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7888 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
7890 configurePowerStatesReport(action
, result
);
7892 return kIOReturnUnsupported
;
7894 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
7896 configureSimplePowerReport(action
, result
);
7898 return kIOReturnUnsupported
;
7903 IOLockLock(reserved
->interruptStatisticsLock
);
7905 /* The array count is signed (because the interrupt indices are signed), hence the cast */
7906 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
7907 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
7909 * If the reporter is currently associated with the statistics
7910 * for an event source, we may need to update the reporter.
7912 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
7913 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
7916 reserved
->interruptStatisticsArray
[cnt
].reporter
->configureReport(channelList
, action
, result
, destination
);
7920 IOLockUnlock(reserved
->interruptStatisticsLock
);
7922 return kIOReturnSuccess
;
7926 IOService::updateReport(IOReportChannelList
*channelList
,
7927 IOReportUpdateAction action
,
7933 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7934 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
7936 updatePowerStatesReport(action
, result
, destination
);
7938 return kIOReturnUnsupported
;
7940 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
7942 updateSimplePowerReport(action
, result
, destination
);
7944 return kIOReturnUnsupported
;
7949 IOLockLock(reserved
->interruptStatisticsLock
);
7951 /* The array count is signed (because the interrupt indices are signed), hence the cast */
7952 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
7953 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
7955 * If the reporter is currently associated with the statistics
7956 * for an event source, we need to update the reporter.
7958 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
7959 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
7962 reserved
->interruptStatisticsArray
[cnt
].reporter
->updateReport(channelList
, action
, result
, destination
);
7966 IOLockUnlock(reserved
->interruptStatisticsLock
);
7968 return kIOReturnSuccess
;
7972 IOService::getAuthorizationID( void )
7974 return reserved
->authorizationID
;
7978 IOService::setAuthorizationID( uint64_t authorizationID
)
7980 OSObject
* entitlement
;
7983 entitlement
= IOUserClient::copyClientEntitlement( current_task(), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
7986 if (entitlement
== kOSBooleanTrue
) {
7987 reserved
->authorizationID
= authorizationID
;
7989 status
= kIOReturnSuccess
;
7991 status
= kIOReturnNotPrivileged
;
7994 entitlement
->release();
7996 status
= kIOReturnNotPrivileged
;
8002 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8006 OSMetaClassDefineReservedUsed(IOService
, 0);
8007 OSMetaClassDefineReservedUsed(IOService
, 1);
8008 OSMetaClassDefineReservedUnused(IOService
, 2);
8009 OSMetaClassDefineReservedUnused(IOService
, 3);
8010 OSMetaClassDefineReservedUnused(IOService
, 4);
8011 OSMetaClassDefineReservedUnused(IOService
, 5);
8012 OSMetaClassDefineReservedUnused(IOService
, 6);
8013 OSMetaClassDefineReservedUnused(IOService
, 7);
8015 OSMetaClassDefineReservedUsed(IOService
, 0);
8016 OSMetaClassDefineReservedUsed(IOService
, 1);
8017 OSMetaClassDefineReservedUsed(IOService
, 2);
8018 OSMetaClassDefineReservedUsed(IOService
, 3);
8019 OSMetaClassDefineReservedUsed(IOService
, 4);
8020 OSMetaClassDefineReservedUsed(IOService
, 5);
8021 OSMetaClassDefineReservedUsed(IOService
, 6);
8022 OSMetaClassDefineReservedUsed(IOService
, 7);
8024 OSMetaClassDefineReservedUnused(IOService
, 8);
8025 OSMetaClassDefineReservedUnused(IOService
, 9);
8026 OSMetaClassDefineReservedUnused(IOService
, 10);
8027 OSMetaClassDefineReservedUnused(IOService
, 11);
8028 OSMetaClassDefineReservedUnused(IOService
, 12);
8029 OSMetaClassDefineReservedUnused(IOService
, 13);
8030 OSMetaClassDefineReservedUnused(IOService
, 14);
8031 OSMetaClassDefineReservedUnused(IOService
, 15);
8032 OSMetaClassDefineReservedUnused(IOService
, 16);
8033 OSMetaClassDefineReservedUnused(IOService
, 17);
8034 OSMetaClassDefineReservedUnused(IOService
, 18);
8035 OSMetaClassDefineReservedUnused(IOService
, 19);
8036 OSMetaClassDefineReservedUnused(IOService
, 20);
8037 OSMetaClassDefineReservedUnused(IOService
, 21);
8038 OSMetaClassDefineReservedUnused(IOService
, 22);
8039 OSMetaClassDefineReservedUnused(IOService
, 23);
8040 OSMetaClassDefineReservedUnused(IOService
, 24);
8041 OSMetaClassDefineReservedUnused(IOService
, 25);
8042 OSMetaClassDefineReservedUnused(IOService
, 26);
8043 OSMetaClassDefineReservedUnused(IOService
, 27);
8044 OSMetaClassDefineReservedUnused(IOService
, 28);
8045 OSMetaClassDefineReservedUnused(IOService
, 29);
8046 OSMetaClassDefineReservedUnused(IOService
, 30);
8047 OSMetaClassDefineReservedUnused(IOService
, 31);
8048 OSMetaClassDefineReservedUnused(IOService
, 32);
8049 OSMetaClassDefineReservedUnused(IOService
, 33);
8050 OSMetaClassDefineReservedUnused(IOService
, 34);
8051 OSMetaClassDefineReservedUnused(IOService
, 35);
8052 OSMetaClassDefineReservedUnused(IOService
, 36);
8053 OSMetaClassDefineReservedUnused(IOService
, 37);
8054 OSMetaClassDefineReservedUnused(IOService
, 38);
8055 OSMetaClassDefineReservedUnused(IOService
, 39);
8056 OSMetaClassDefineReservedUnused(IOService
, 40);
8057 OSMetaClassDefineReservedUnused(IOService
, 41);
8058 OSMetaClassDefineReservedUnused(IOService
, 42);
8059 OSMetaClassDefineReservedUnused(IOService
, 43);
8060 OSMetaClassDefineReservedUnused(IOService
, 44);
8061 OSMetaClassDefineReservedUnused(IOService
, 45);
8062 OSMetaClassDefineReservedUnused(IOService
, 46);
8063 OSMetaClassDefineReservedUnused(IOService
, 47);