]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOCommandGate.cpp
51e33dac53b768130bf941885c14e9d028e41052
[apple/xnu.git] / iokit / Kernel / IOCommandGate.cpp
1 /*
2 * Copyright (c) 1998-2000 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 #include <libkern/OSDebug.h>
31
32 #include <IOKit/IOCommandGate.h>
33 #include <IOKit/IOWorkLoop.h>
34 #include <IOKit/IOReturn.h>
35 #include <IOKit/IOTimeStamp.h>
36
37 #define super IOEventSource
38
39 OSDefineMetaClassAndStructors(IOCommandGate, IOEventSource)
40 OSMetaClassDefineReservedUnused(IOCommandGate, 0);
41 OSMetaClassDefineReservedUnused(IOCommandGate, 1);
42 OSMetaClassDefineReservedUnused(IOCommandGate, 2);
43 OSMetaClassDefineReservedUnused(IOCommandGate, 3);
44 OSMetaClassDefineReservedUnused(IOCommandGate, 4);
45 OSMetaClassDefineReservedUnused(IOCommandGate, 5);
46 OSMetaClassDefineReservedUnused(IOCommandGate, 6);
47 OSMetaClassDefineReservedUnused(IOCommandGate, 7);
48
49 bool IOCommandGate::checkForWork() { return false; }
50
51 bool IOCommandGate::init(OSObject *inOwner, Action inAction)
52 {
53 return super::init(inOwner, (IOEventSource::Action) inAction);
54 }
55
56 IOCommandGate *
57 IOCommandGate::commandGate(OSObject *inOwner, Action inAction)
58 {
59 IOCommandGate *me = new IOCommandGate;
60
61 if (me && !me->init(inOwner, inAction)) {
62 me->release();
63 return 0;
64 }
65
66 return me;
67 }
68
69 /* virtual */ void IOCommandGate::disable()
70 {
71 if (workLoop && !workLoop->inGate())
72 OSReportWithBacktrace("IOCommandGate::disable() called when not gated");
73
74 super::disable();
75 }
76
77 /* virtual */ void IOCommandGate::enable()
78 {
79 if (workLoop) {
80 closeGate();
81 super::enable();
82 wakeupGate(&enabled, /* oneThread */ false); // Unblock sleeping threads
83 openGate();
84 }
85 }
86
87 /* virtual */ void IOCommandGate::free()
88 {
89 setWorkLoop(0);
90 super::free();
91 }
92
93 /* virtual */ void IOCommandGate::setWorkLoop(IOWorkLoop *inWorkLoop)
94 {
95 uintptr_t *sleepersP = (uintptr_t *) &reserved;
96 if (!inWorkLoop && workLoop) { // tearing down
97 closeGate();
98 *sleepersP |= 1;
99 while (*sleepersP >> 1) {
100 thread_wakeup_with_result(&enabled, THREAD_INTERRUPTED);
101 sleepGate(sleepersP, THREAD_UNINT);
102 }
103 *sleepersP = 0;
104 openGate();
105 }
106 else
107
108 super::setWorkLoop(inWorkLoop);
109 }
110
111 IOReturn IOCommandGate::runCommand(void *arg0, void *arg1,
112 void *arg2, void *arg3)
113 {
114 return runAction((Action) action, arg0, arg1, arg2, arg3);
115 }
116
117 IOReturn IOCommandGate::attemptCommand(void *arg0, void *arg1,
118 void *arg2, void *arg3)
119 {
120 return attemptAction((Action) action, arg0, arg1, arg2, arg3);
121 }
122
123 IOReturn IOCommandGate::runAction(Action inAction,
124 void *arg0, void *arg1,
125 void *arg2, void *arg3)
126 {
127 if (!inAction)
128 return kIOReturnBadArgument;
129
130 IOTimeStampConstant(IODBG_CMDQ(IOCMDQ_ACTION),
131 (unsigned int) inAction, (unsigned int) owner);
132
133 // closeGate is recursive needn't worry if we already hold the lock.
134 closeGate();
135
136 // If the command gate is disabled and we aren't on the workloop thread
137 // itself then sleep until we get enabled.
138 IOReturn res;
139 if (!workLoop->onThread()) {
140 while (!enabled) {
141 uintptr_t *sleepersP = (uintptr_t *) &reserved;
142
143 *sleepersP += 2;
144 IOReturn res = sleepGate(&enabled, THREAD_ABORTSAFE);
145 *sleepersP -= 2;
146
147 bool wakeupTearDown = (*sleepersP & 1);
148 if (res || wakeupTearDown) {
149 openGate();
150
151 if (wakeupTearDown)
152 commandWakeup(sleepersP); // No further resources used
153
154 return kIOReturnAborted;
155 }
156 }
157 }
158
159 // Must be gated and on the work loop or enabled
160 res = (*inAction)(owner, arg0, arg1, arg2, arg3);
161 openGate();
162
163 return res;
164 }
165
166 IOReturn IOCommandGate::attemptAction(Action inAction,
167 void *arg0, void *arg1,
168 void *arg2, void *arg3)
169 {
170 IOReturn res;
171
172 if (!inAction)
173 return kIOReturnBadArgument;
174
175 // Try to close the gate if can't get return immediately.
176 if (!tryCloseGate())
177 return kIOReturnCannotLock;
178
179 // If the command gate is disabled then sleep until we get a wakeup
180 if (!workLoop->onThread() && !enabled)
181 res = kIOReturnNotPermitted;
182 else {
183 IOTimeStampConstant(IODBG_CMDQ(IOCMDQ_ACTION),
184 (unsigned int) inAction, (unsigned int) owner);
185
186 res = (*inAction)(owner, arg0, arg1, arg2, arg3);
187 }
188
189 openGate();
190
191 return res;
192 }
193
194 IOReturn IOCommandGate::commandSleep(void *event, UInt32 interruptible)
195 {
196 if (!workLoop->inGate())
197 return kIOReturnNotPermitted;
198
199 return sleepGate(event, interruptible);
200 }
201
202 void IOCommandGate::commandWakeup(void *event, bool oneThread)
203 {
204 wakeupGate(event, oneThread);
205 }