|
|
1.1 root 1: /*
2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
24:
25: HISTORY
26: 1998-7-13 Godfrey van der Linden(gvdl)
27: Created.
28: */
29: #include <IOKit/IOWorkLoop.h>
30: #include <IOKit/IOEventSource.h>
31: #include <IOKit/IOInterruptEventSource.h>
32: #include <IOKit/IOCommandGate.h>
33: #include <IOKit/IOTimeStamp.h>
34:
35: #define super OSObject
36:
37: OSDefineMetaClassAndStructors(IOWorkLoop, OSObject)
38:
39: void IOWorkLoop::launchThreadMain(void *self)
40: {
41: IOWorkLoop *me = (IOWorkLoop *) self;
42: register thread_t mythread = current_thread();
43:
44: // Make sure that this thread always has a kernel stack
45: stack_privilege(mythread);
46: thread_set_cont_arg((int) me);
47: threadMainContinuation();
48: }
49:
50: bool IOWorkLoop::init()
51: {
52: // The super init and gateLock allocation MUST be done first
53: if ( !super::init() || !(gateLock = IORecursiveLockAlloc()) )
54: return false;
55:
56: if ( !(workToDoLock = IOSimpleLockAlloc()) )
57: return false;
58: IOSimpleLockInit(workToDoLock);
59: workToDo = false;
60:
61: controlG = IOCommandGate::commandGate(this,
62: (IOCommandGate::Action) &IOWorkLoop::_maintRequest);
63: if ( !controlG )
64: return false;
65:
66: // Point the controlGate at the workLoop. Usually addEventSource
67: // does this automatically. The problem is in this case addEventSource
68: // uses the control gate and it has to be bootstrapped.
69: controlG->setWorkLoop(this);
70: if (addEventSource(controlG) != kIOReturnSuccess)
71: return false;
72:
73: workThread = IOCreateThread(launchThreadMain, (void *) this);
74: if (!workThread)
75: return false;
76:
77: return true;
78: }
79:
80: IOWorkLoop *
81: IOWorkLoop::workLoop()
82: {
83: IOWorkLoop *me = new IOWorkLoop;
84:
85: if (me && !me->init()) {
86: me->free();
87: return 0;
88: }
89:
90: return me;
91: }
92:
93: void IOWorkLoop::free()
94: {
95: // Hmm, we didn't even acquire the gate lock succesfully...
96: if (!gateLock) {
97: super::free(); // ... so just issue a super free
98: return; // and return immediately
99: }
100:
101: if (workThread && !onThread())
102: closeGate();
103:
104: if (controlG) {
105: IOCommandGate *tmpControlG = controlG;
106: controlG = 0;
107: tmpControlG->release();
108: }
109:
110: disableAllEventSources();
111:
112: // Partial initialisation no thread yet so get rid of event sources.
113: if (!workThread && eventChain) {
114: IOEventSource *event, *next;
115:
116: for (event = eventChain; event; event = next) {
117: next = event->getNext();
118: event->release();
119: }
120: eventChain = 0;
121: }
122:
123: // This is safe as we have disabled all of our interrupt event sources.
124: if (workToDoLock) {
125: IOSimpleLockFree(workToDoLock);
126: workToDoLock = 0;
127: }
128:
129: //
130: // Three cases:
131: // 1> If I don't have a work thread yet just delete the command gate and
132: // free the super class
133: // 2> If I have a work loop and I'm on the thread, then one of the event
134: // sources must be issueing a free request. In which case we issue a
135: // loop restart request and return for the main loop to detect.
136: // 3> Client free request. The workToDoLock being set to 0 is a signal
137: // for the main thread to wake up and kill itself.
138: //
139: if (!workThread) {
140: IORecursiveLockFree(gateLock);
141: super::free();
142: }
143: else if (onThread())
144: loopRestart = true;
145: else {
146: thread_wakeup_one((void *) &workToDo); // Wakeup any sleepers
147: openGate();
148: }
149: }
150:
151: IOReturn IOWorkLoop::addEventSource(IOEventSource *newEvent)
152: {
153: return controlG->runCommand((void *) mAddEvent, (void *) newEvent);
154: }
155:
156: IOReturn IOWorkLoop::removeEventSource(IOEventSource *toRemove)
157: {
158: return controlG->runCommand((void *) mRemoveEvent, (void *) toRemove);
159: }
160:
161: void IOWorkLoop::enableAllEventSources() const
162: {
163: IOEventSource *event;
164:
165: for (event = eventChain; event; event = event->getNext())
166: event->enable();
167: }
168:
169: void IOWorkLoop::disableAllEventSources() const
170: {
171: IOEventSource *event;
172:
173: for (event = eventChain; event; event = event->getNext())
174: event->disable();
175: }
176:
177: void IOWorkLoop::enableAllInterrupts() const
178: {
179: IOEventSource *event;
180:
181: for (event = eventChain; event; event = event->getNext())
182: if (OSDynamicCast(IOInterruptEventSource, event))
183: event->enable();
184: }
185:
186: void IOWorkLoop::disableAllInterrupts() const
187: {
188: IOEventSource *event;
189:
190: for (event = eventChain; event; event = event->getNext())
191: if (OSDynamicCast(IOInterruptEventSource, event))
192: event->disable();
193: }
194:
195: #if KDEBUG
196: #define IOTimeClientS() \
197: do { \
198: IOTimeStampStart(IODBG_WORKLOOP(IOWL_CLIENT), \
199: (unsigned int) this, (unsigned int) event); \
200: } while(0)
201:
202: #define IOTimeClientE() \
203: do { \
204: IOTimeStampEnd(IODBG_WORKLOOP(IOWL_CLIENT), \
205: (unsigned int) this, (unsigned int) event); \
206: } while(0)
207:
208: #define IOTimeWorkS() \
209: do { \
210: IOTimeStampStart(IODBG_WORKLOOP(IOWL_WORK), (unsigned int) this); \
211: } while(0)
212:
213: #define IOTimeWorkE() \
214: do { \
215: IOTimeStampEnd(IODBG_WORKLOOP(IOWL_WORK),(unsigned int) this); \
216: } while(0)
217:
218: #else /* !KDEBUG */
219:
220: #define IOTimeClientS()
221: #define IOTimeClientE()
222: #define IOTimeWorkS()
223: #define IOTimeWorkE()
224:
225: #endif /* KDEBUG */
226:
227: void IOWorkLoop::threadMainContinuation()
228: {
229: IOWorkLoop* self;
230: self = (IOWorkLoop *) thread_get_cont_arg();
231:
232: self->threadMain();
233: }
234:
235: void IOWorkLoop::threadMain()
236: {
237: loopRestart = false;
238:
239: for (;;) {
240: bool more;
241:
242: IOTimeWorkS();
243:
244: closeGate();
245: if (!workToDoLock)
246: goto exitThread;
247:
248: do {
249: IOEventSource *event;
250:
251: restartLoop:
252:
253: workToDo = more = false;
254: for (event = eventChain; event; event = event->getNext()) {
255:
256: IOTimeClientS();
257: more |= event->checkForWork();
258: IOTimeClientE();
259:
260: if (!workToDoLock)
261: goto exitThread;
262: else if (loopRestart) {
263: loopRestart = false;
264:
265: goto restartLoop;
266: }
267: }
268: } while (more);
269:
270: IOTimeWorkE();
271:
272: openGate();
273:
274: if (workToDoLock) {
275: IOInterruptState is;
276:
277: is = IOSimpleLockLockDisableInterrupt(workToDoLock);
278: if (!workToDo) {
279: assert_wait((void *) &workToDo, false);
280: IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
281: thread_block(&threadMainContinuation);
282: /* NOTREACHED */
283: }
284: else
285: IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
286: }
287:
288: if (!workToDoLock) {
289: IOEventSource *event, *next;
290: exitThread:
291:
292: for (event = eventChain; event; event = next) {
293: next = event->getNext();
294: event->release();
295: }
296: eventChain = 0;
297:
298: IORecursiveLockFree(gateLock);
299: super::free();
300: IOExitThread(0);
301: }
302: }
303: }
304:
305: IOThread IOWorkLoop::getThread() const
306: {
307: return workThread;
308: }
309:
310: bool IOWorkLoop::onThread() const
311: {
312: return (IOThreadSelf() == workThread);
313: }
314:
315: bool IOWorkLoop::inGate() const
316: {
317: return IORecursiveLockHaveLock(gateLock);
318: }
319:
320: // Internal APIs used by event sources to control the thread
321: void IOWorkLoop::signalWorkAvailable()
322: {
323: if (workToDoLock) {
324: IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
325: workToDo = true;
326: thread_wakeup_one((void *) &workToDo);
327: IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
328: }
329: }
330:
331: void IOWorkLoop::openGate()
332: {
333: IORecursiveLockUnlock(gateLock);
334: }
335:
336: void IOWorkLoop::closeGate()
337: {
338: IORecursiveLockLock(gateLock);
339: }
340:
341: IOReturn IOWorkLoop::_maintRequest(void *inC, void *inD, void *, void *)
342: {
343: maintCommandEnum command = (maintCommandEnum) (vm_address_t) inC;
344: IOEventSource *inEvent = (IOEventSource *) inD;
345: IOReturn res = kIOReturnSuccess;
346:
347: switch (command)
348: {
349: case mAddEvent:
350: loopRestart = true;
351: inEvent->retain();
352: inEvent->setWorkLoop(this);
353: inEvent->setNext(0);
354:
355: if (!eventChain)
356: eventChain = inEvent;
357: else {
358: IOEventSource *event, *next;
359:
360: for (event = eventChain; (next = event->getNext()); event = next)
361: ;
362: event->setNext(inEvent);
363: }
364: break;
365:
366: case mRemoveEvent:
367: if (eventChain == inEvent)
368: eventChain = inEvent->getNext();
369: else {
370: IOEventSource *event, *next;
371:
372: event = eventChain;
373: while ((next = event->getNext()) && next != inEvent)
374: event = next;
375:
376: if (!next) {
377: res = kIOReturnBadArgument;
378: break;
379: }
380: event->setNext(inEvent->getNext());
381: }
382:
383: inEvent->setWorkLoop(0);
384: inEvent->setNext(0);
385: inEvent->release();
386: loopRestart = true;
387: break;
388:
389: default:
390: return kIOReturnUnsupported;
391: }
392:
393: return res;
394: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.