2  * Copyright (c) 2017 Apple Inc. All rights reserved. 
   5 #include <IOKit/perfcontrol/IOPerfControl.h> 
   9 #include <kern/thread_group.h> 
  12 #define super OSObject 
  13 OSDefineMetaClassAndStructors(IOPerfControlClient
, OSObject
); 
  16 IOPerfControlClient::init(IOService 
*driver
, uint64_t maxWorkCapacity
) 
  22         interface 
= PerfControllerInterface
{ 
  25                     [](IOService 
*device
) { 
  26                             return kIOReturnSuccess
; 
  29                     [](IOService 
*device
) { 
  30                             return kIOReturnSuccess
; 
  33                     [](IOService 
*device
, PerfControllerInterface::WorkState 
*state
, WorkSubmitArgs 
*args
) { 
  37                     [](IOService 
*device
, uint64_t token
, PerfControllerInterface::WorkState 
*state
, WorkSubmitArgs 
*args
) { 
  40                     [](IOService 
*device
, uint64_t token
, PerfControllerInterface::WorkState 
*state
, WorkBeginArgs 
*args
) { 
  43                     [](IOService 
*device
, uint64_t token
, PerfControllerInterface::WorkState 
*state
, WorkEndArgs 
*args
, bool done
) { 
  47         interfaceLock 
= IOLockAlloc(); 
  52         deviceRegistrationList 
= OSSet::withCapacity(4); 
  53         if (!deviceRegistrationList
) { 
  57         bzero(workTable
, sizeof(workTable
)); 
  58         memset(&workTable
[kIOPerfControlClientWorkUntracked
], ~0, sizeof(WorkTableEntry
)); 
  59         workTableNextIndex 
= kIOPerfControlClientWorkUntracked 
+ 1; 
  61         workTableLock 
= IOSimpleLockAlloc(); 
  66         // TODO: check sum(maxWorkCapacities) < table size 
  72                 IOLockFree(interfaceLock
); 
  74         if (deviceRegistrationList
) { 
  75                 deviceRegistrationList
->release(); 
  78                 IOSimpleLockFree(workTableLock
); 
  83 IOPerfControlClient 
*_Atomic gSharedClient 
= nullptr; 
  86 IOPerfControlClient::copyClient(IOService 
*driver
, uint64_t maxWorkCapacity
) 
  88         IOPerfControlClient 
*client 
= atomic_load_explicit(&gSharedClient
, memory_order_acquire
); 
  89         if (client 
== nullptr) { 
  90                 IOPerfControlClient 
*expected 
= client
; 
  91                 client 
= new IOPerfControlClient
; 
  92                 if (!client 
|| !client
->init(driver
, maxWorkCapacity
)) { 
  93                         panic("could not create IOPerfControlClient"); 
  95                 if (!atomic_compare_exchange_strong_explicit(&gSharedClient
, &expected
, client
, memory_order_acq_rel
, 
  96                     memory_order_acquire
)) { 
 101         // TODO: add maxWorkCapacity to existing client 
 107 IOPerfControlClient::allocateToken(thread_group 
*thread_group
) 
 109         uint64_t token 
= kIOPerfControlClientWorkUntracked
; 
 116 IOPerfControlClient::deallocateToken(uint64_t token
) 
 121 IOPerfControlClient::getEntryForToken(uint64_t token
, IOPerfControlClient::WorkTableEntry 
&entry
) 
 123         if (token 
== kIOPerfControlClientWorkUntracked
) { 
 127         if (token 
>= kWorkTableNumEntries
) { 
 128                 panic("Invalid work token (%llu): index out of bounds.", token
); 
 131         entry 
= workTable
[token
]; 
 132         auto *thread_group 
= entry
.thread_group
; 
 133         assertf(thread_group
, "Invalid work token: %llu", token
); 
 134         return thread_group 
!= nullptr; 
 138 IOPerfControlClient::markEntryStarted(uint64_t token
, bool started
) 
 140         if (token 
== kIOPerfControlClientWorkUntracked
) { 
 144         if (token 
>= kWorkTableNumEntries
) { 
 145                 panic("Invalid work token (%llu): index out of bounds.", token
); 
 148         workTable
[token
].started 
= started
; 
 152 IOPerfControlClient::registerDevice(__unused IOService 
*driver
, IOService 
*device
) 
 154         IOReturn ret 
= kIOReturnSuccess
; 
 156         IOLockLock(interfaceLock
); 
 158         if (interface
.version 
> 0) { 
 159                 ret 
= interface
.registerDevice(device
); 
 161                 deviceRegistrationList
->setObject(device
); 
 164         IOLockUnlock(interfaceLock
); 
 170 IOPerfControlClient::unregisterDevice(__unused IOService 
*driver
, IOService 
*device
) 
 172         IOLockLock(interfaceLock
); 
 174         if (interface
.version 
> 0) { 
 175                 interface
.unregisterDevice(device
); 
 177                 deviceRegistrationList
->removeObject(device
); 
 180         IOLockUnlock(interfaceLock
); 
 184 IOPerfControlClient::workSubmit(IOService 
*device
, WorkSubmitArgs 
*args
) 
 186         return kIOPerfControlClientWorkUntracked
; 
 190 IOPerfControlClient::workSubmitAndBegin(IOService 
*device
, WorkSubmitArgs 
*submitArgs
, WorkBeginArgs 
*beginArgs
) 
 192         return kIOPerfControlClientWorkUntracked
; 
 196 IOPerfControlClient::workBegin(IOService 
*device
, uint64_t token
, WorkBeginArgs 
*args
) 
 201 IOPerfControlClient::workEnd(IOService 
*device
, uint64_t token
, WorkEndArgs 
*args
, bool done
) 
 206 IOPerfControlClient::registerPerformanceController(PerfControllerInterface pci
) 
 208         IOReturn result 
= kIOReturnError
; 
 210         IOLockLock(interfaceLock
); 
 212         if (interface
.version 
== 0 && pci
.version 
> 0) { 
 213                 assert(pci
.registerDevice 
&& pci
.unregisterDevice 
&& pci
.workCanSubmit 
&& pci
.workSubmit 
&& pci
.workBegin 
&& pci
.workEnd
); 
 214                 result 
= kIOReturnSuccess
; 
 217                 while ((obj 
= deviceRegistrationList
->getAnyObject())) { 
 218                         IOService 
*device 
= OSDynamicCast(IOService
, obj
); 
 220                                 pci
.registerDevice(device
); 
 222                         deviceRegistrationList
->removeObject(obj
); 
 228         IOLockUnlock(interfaceLock
);