]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMWorkArbiter.cpp
0cfa311f2c969f43b6e01a779686fd8a40f67cd3
[apple/xnu.git] / iokit / Kernel / IOPMWorkArbiter.cpp
1 /*
2 * Copyright (c) 2001-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30
31 #include "IOPMWorkArbiter.h"
32 #include "IOKit/IOLocks.h"
33 #undef super
34 #define super IOEventSource
35 OSDefineMetaClassAndStructors(IOPMWorkArbiter, IOEventSource);
36
37 /*************************************************************************/
38 static
39 void * _dequeue(void ** inList, SInt32 inOffset)
40 {
41 void * oldListHead;
42 void * newListHead;
43
44 do {
45 oldListHead = *inList;
46 if (oldListHead == NULL) {
47 break;
48 }
49
50 newListHead = *(void **) (((char *) oldListHead) + inOffset);
51 } while (! OSCompareAndSwap((UInt32)oldListHead,
52 (UInt32)newListHead, (UInt32 *)inList));
53 return oldListHead;
54 }
55
56 /*************************************************************************/
57 static
58 void _enqueue(void ** inList, void * inNewLink, SInt32 inOffset)
59 {
60 void * oldListHead;
61 void * newListHead = inNewLink;
62 void ** newLinkNextPtr = (void **) (((char *) inNewLink) + inOffset);
63
64 do {
65 oldListHead = *inList;
66 *newLinkNextPtr = oldListHead;
67 } while (! OSCompareAndSwap((UInt32)oldListHead, (UInt32)newListHead,
68 (UInt32 *)inList));
69 }
70
71 /*************************************************************************/
72 IOPMWorkArbiter *IOPMWorkArbiter::pmWorkArbiter(
73 IOPMrootDomain *inOwner)
74 {
75 IOPMWorkArbiter *me = new IOPMWorkArbiter;
76
77 if(me && !me->init((OSObject *)inOwner, 0) )
78 {
79 me->release();
80 return NULL;
81 }
82
83 return me;
84 }
85
86 /*************************************************************************/
87 bool IOPMWorkArbiter::init(OSObject *owner, Action action)
88 {
89 if(!(super::init(owner, (IOEventSource::Action) action)))
90 return false;
91
92 events = NULL;
93 fRootDomain = (IOPMrootDomain *)owner;
94
95 if (!(tmpLock = IOLockAlloc())) {
96 panic("IOPMWorkArbiter::init can't alloc lock");
97 }
98 return true;
99 }
100
101 /*************************************************************************/
102 bool IOPMWorkArbiter::driverAckedOccurred(IOService *inTarget)
103 {
104 PMEventEntry *new_one = NULL;
105
106 new_one = (PMEventEntry *)IOMalloc(sizeof(PMEventEntry));
107 if(!new_one) return false;
108
109 new_one->actionType = IOPMWorkArbiter::kDriverAcked;
110 new_one->target = inTarget;
111
112 // Change to queue
113 IOLockLock(tmpLock);
114 _enqueue((void **)&events, (void *)new_one, 0);
115 IOLockUnlock(tmpLock);
116 signalWorkAvailable();
117
118 return true;
119 }
120
121 /*************************************************************************/
122 bool IOPMWorkArbiter::allAckedOccurred(IOService *inTarget)
123 {
124 PMEventEntry *new_one = NULL;
125
126 new_one = (PMEventEntry *)IOMalloc(sizeof(PMEventEntry));
127 if(!new_one) return false;
128
129 new_one->actionType = IOPMWorkArbiter::kAllAcked;
130 new_one->target = inTarget;
131
132 // Change to queue
133 IOLockLock(tmpLock);
134 _enqueue((void **)&events, (void *)new_one, 0);
135 IOLockUnlock(tmpLock);
136 signalWorkAvailable();
137
138 return true;
139 }
140
141 /*************************************************************************/
142 bool IOPMWorkArbiter::clamshellStateChangeOccurred(uint32_t messageValue)
143 {
144 PMEventEntry *new_one = NULL;
145
146 new_one = (PMEventEntry *)IOMalloc(sizeof(PMEventEntry));
147 if(!new_one) return false;
148
149 new_one->actionType = IOPMWorkArbiter::kRootDomainClamshellChanged;
150 new_one->target = (IOService *)fRootDomain;
151 new_one->intArgument = messageValue;
152
153 IOLockLock(tmpLock);
154 _enqueue((void **)&events, (void *)new_one, 0);
155 IOLockUnlock(tmpLock);
156 signalWorkAvailable();
157
158 return true;
159 }
160
161
162 /*************************************************************************/
163 void IOPMWorkArbiter::checkForWorkThreadFunc(void *refcon)
164 {
165 PMEventEntry *theNode = (PMEventEntry *)refcon;
166 IOService *theTarget;
167 UInt16 theAction;
168
169 if(!theNode) return;
170 theTarget = theNode->target;
171 theAction = theNode->actionType;
172 IOFree(theNode, sizeof(PMEventEntry));
173 theNode = NULL;
174
175 switch (theAction)
176 {
177 case kAllAcked:
178 theTarget->all_acked_threaded();
179 break;
180
181 case kDriverAcked:
182 theTarget->driver_acked_threaded();
183 break;
184 }
185
186 }
187
188
189 /*************************************************************************/
190 // checkForWork() is called in a gated context
191 bool IOPMWorkArbiter::checkForWork()
192 {
193 PMEventEntry *theNode;
194 IOService *theTarget;
195 UInt16 theAction;
196
197 // Dequeue and process the state change request
198 IOLockLock(tmpLock);
199 if((theNode = (PMEventEntry *)_dequeue((void **)&events, 0)))
200 {
201 IOLockUnlock(tmpLock);
202 theTarget = theNode->target;
203 theAction = theNode->actionType;
204 IOFree((void *)theNode, sizeof(PMEventEntry));
205
206 switch (theAction)
207 {
208 case kAllAcked:
209 theTarget->all_acked_threaded();
210 break;
211
212 case kDriverAcked:
213 theTarget->driver_acked_threaded();
214 break;
215
216 case kRootDomainClamshellChanged:
217 theTarget->messageClients(
218 kIOPMMessageClamshellStateChange,
219 (void *)theNode->intArgument);
220 break;
221 }
222 }
223 else {
224 IOLockUnlock(tmpLock);
225 }
226 // Return true if there's more work to be done
227 if(events) return true;
228 else return false;
229 }
230
231
232 /*************************************************************************/
233
234 /*************************************************************************/
235
236 /*************************************************************************/
237
238 /*************************************************************************/
239 /*
240 #undef super
241 #define super OSObject
242
243 PMWorkerThread *PMWorkerThread::workerThread( IOPMWorkArbiter *inArbiter )
244 {
245 PMWorkerThread * inst;
246
247 if( !(inst = new PMWorkerThread) )
248 goto exit;
249
250 if( !inst->init() )
251 goto exit;
252
253 inst->arbiter = inArbiter;
254
255 if( !(IOCreateThread((IOThreadFunc) &PMWorkerThread::main, inst)) )
256 goto exit;
257
258 return inst;
259
260 exit:
261 if(inst)
262 inst->release();
263
264 return NULL;
265 }
266
267 void PMWorkerThread::free( void )
268 {
269 super::free();
270 }
271
272 void PMWorkerThread::main( PMWorkerThread * self )
273 {
274 PMWorkUnit *job;
275 IOService *who;
276
277 do {
278 // Get a new job
279
280 IOTakeLock( gJobsLock );
281
282 if( !(job = (PMWorkUnit *) gJobs->copyNextJob()) )
283 {
284 IOUnlock( gJobsLock );
285 semaphore_wait( gJobsSemaphore );
286 IOTakeLock( gJobsLock );
287
288 job = (PMWorkUnit *) gJobs->copyNextJob();
289 }
290
291 IOUnlock( gJobsLock );
292
293 if(job)
294 {
295 who = job->who;
296
297 // Do job
298 switch(job->type)
299 {
300 case kMatchNubJob:
301 if(who)
302 who->doServiceMatch();
303 break;
304
305 default:
306 break;
307 }
308 }
309
310 } while( alive );
311
312 self->release();
313 }
314
315 */