]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPerfControl.cpp
xnu-4903.270.47.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPerfControl.cpp
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 */
4
5 #include <IOKit/perfcontrol/IOPerfControl.h>
6
7 #include <stdatomic.h>
8
9 #include <kern/thread_group.h>
10
11 #undef super
12 #define super OSObject
13 OSDefineMetaClassAndStructors(IOPerfControlClient, OSObject);
14
15 bool
16 IOPerfControlClient::init(IOService *driver, uint64_t maxWorkCapacity)
17 {
18 if (!super::init()) {
19 return false;
20 }
21
22 interface = PerfControllerInterface{
23 .version = 0,
24 .registerDevice =
25 [](IOService *device) {
26 return kIOReturnSuccess;
27 },
28 .unregisterDevice =
29 [](IOService *device) {
30 return kIOReturnSuccess;
31 },
32 .workCanSubmit =
33 [](IOService *device, PerfControllerInterface::WorkState *state, WorkSubmitArgs *args) {
34 return false;
35 },
36 .workSubmit =
37 [](IOService *device, uint64_t token, PerfControllerInterface::WorkState *state, WorkSubmitArgs *args) {
38 },
39 .workBegin =
40 [](IOService *device, uint64_t token, PerfControllerInterface::WorkState *state, WorkBeginArgs *args) {
41 },
42 .workEnd =
43 [](IOService *device, uint64_t token, PerfControllerInterface::WorkState *state, WorkEndArgs *args, bool done) {
44 },
45 };
46
47 interfaceLock = IOLockAlloc();
48 if (!interfaceLock) {
49 goto error;
50 }
51
52 deviceRegistrationList = OSSet::withCapacity(4);
53 if (!deviceRegistrationList) {
54 goto error;
55 }
56
57 bzero(workTable, sizeof(workTable));
58 memset(&workTable[kIOPerfControlClientWorkUntracked], ~0, sizeof(WorkTableEntry));
59 workTableNextIndex = kIOPerfControlClientWorkUntracked + 1;
60
61 workTableLock = IOSimpleLockAlloc();
62 if (!workTableLock) {
63 goto error;
64 }
65
66 // TODO: check sum(maxWorkCapacities) < table size
67
68 return true;
69
70 error:
71 if (interfaceLock) {
72 IOLockFree(interfaceLock);
73 }
74 if (deviceRegistrationList) {
75 deviceRegistrationList->release();
76 }
77 if (workTableLock) {
78 IOSimpleLockFree(workTableLock);
79 }
80 return false;
81 }
82
83 IOPerfControlClient *_Atomic gSharedClient = nullptr;
84
85 IOPerfControlClient *
86 IOPerfControlClient::copyClient(IOService *driver, uint64_t maxWorkCapacity)
87 {
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");
94 }
95 if (!atomic_compare_exchange_strong_explicit(&gSharedClient, &expected, client, memory_order_acq_rel,
96 memory_order_acquire)) {
97 client->release();
98 client = expected;
99 }
100 }
101 // TODO: add maxWorkCapacity to existing client
102 client->retain();
103 return client;
104 }
105
106 uint64_t
107 IOPerfControlClient::allocateToken(thread_group *thread_group)
108 {
109 uint64_t token = kIOPerfControlClientWorkUntracked;
110
111
112 return token;
113 }
114
115 void
116 IOPerfControlClient::deallocateToken(uint64_t token)
117 {
118 }
119
120 bool
121 IOPerfControlClient::getEntryForToken(uint64_t token, IOPerfControlClient::WorkTableEntry &entry)
122 {
123 if (token == kIOPerfControlClientWorkUntracked) {
124 return false;
125 }
126
127 if (token >= kWorkTableNumEntries) {
128 panic("Invalid work token (%llu): index out of bounds.", token);
129 }
130
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;
135 }
136
137 void
138 IOPerfControlClient::markEntryStarted(uint64_t token, bool started)
139 {
140 if (token == kIOPerfControlClientWorkUntracked) {
141 return;
142 }
143
144 if (token >= kWorkTableNumEntries) {
145 panic("Invalid work token (%llu): index out of bounds.", token);
146 }
147
148 workTable[token].started = started;
149 }
150
151 IOReturn
152 IOPerfControlClient::registerDevice(__unused IOService *driver, IOService *device)
153 {
154 IOReturn ret = kIOReturnSuccess;
155
156 IOLockLock(interfaceLock);
157
158 if (interface.version > 0) {
159 ret = interface.registerDevice(device);
160 } else {
161 deviceRegistrationList->setObject(device);
162 }
163
164 IOLockUnlock(interfaceLock);
165
166 return ret;
167 }
168
169 void
170 IOPerfControlClient::unregisterDevice(__unused IOService *driver, IOService *device)
171 {
172 IOLockLock(interfaceLock);
173
174 if (interface.version > 0) {
175 interface.unregisterDevice(device);
176 } else {
177 deviceRegistrationList->removeObject(device);
178 }
179
180 IOLockUnlock(interfaceLock);
181 }
182
183 uint64_t
184 IOPerfControlClient::workSubmit(IOService *device, WorkSubmitArgs *args)
185 {
186 return kIOPerfControlClientWorkUntracked;
187 }
188
189 uint64_t
190 IOPerfControlClient::workSubmitAndBegin(IOService *device, WorkSubmitArgs *submitArgs, WorkBeginArgs *beginArgs)
191 {
192 return kIOPerfControlClientWorkUntracked;
193 }
194
195 void
196 IOPerfControlClient::workBegin(IOService *device, uint64_t token, WorkBeginArgs *args)
197 {
198 }
199
200 void
201 IOPerfControlClient::workEnd(IOService *device, uint64_t token, WorkEndArgs *args, bool done)
202 {
203 }
204
205 IOReturn
206 IOPerfControlClient::registerPerformanceController(PerfControllerInterface pci)
207 {
208 IOReturn result = kIOReturnError;
209
210 IOLockLock(interfaceLock);
211
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;
215
216 OSObject *obj;
217 while ((obj = deviceRegistrationList->getAnyObject())) {
218 IOService *device = OSDynamicCast(IOService, obj);
219 if (device) {
220 pci.registerDevice(device);
221 }
222 deviceRegistrationList->removeObject(obj);
223 }
224
225 interface = pci;
226 }
227
228 IOLockUnlock(interfaceLock);
229
230 return result;
231 }