|
|
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/IOCommandQueue.h>
30: #include <IOKit/IOWorkLoop.h>
31: #include <IOKit/IOTimeStamp.h>
32:
33: #include <mach/sync_policy.h>
34:
35: #define NUM_FIELDS_IN_COMMAND 4
36: typedef struct commandEntryTag {
37: void *f[NUM_FIELDS_IN_COMMAND];
38: } commandEntryT;
39:
40: #define super IOEventSource
41:
42: OSDefineMetaClassAndStructors(IOCommandQueue, IOEventSource)
43:
44: /*[
45: Instance Methods
46:
47: initWithNext:owner:action:size:
48: - initWithNext: (IOEventSource *) inNext
49: owner: (id) inOwner
50: action: (SEL) inAction
51: size: (int) inSize;
52:
53: Primary initialiser for the IOCommandQueue class. Returns an
54: IOCommandQueue object that is initialised with the next object in
55: the chain and the owner and action. On return the signalWorkAvailableIMP
56: has been cached for this function.
57:
58: If the object fails to initialise for some reason then [self free] will
59: be called and nil will be returned.
60:
61: See also: initWithNext:owner:action:(IOEventSource)
62: ]*/
63: bool IOCommandQueue::init(OSObject *inOwner,
64: IOCommandQueueAction inAction,
65: int inSize)
66: {
67: if ( !super::init(inOwner, (IOEventSourceAction) inAction) )
68: return false;
69:
70: if (KERN_SUCCESS
71: != semaphore_create(kernel_task, &producerSema, SYNC_POLICY_FIFO, inSize))
72: return false;
73:
74: size = inSize + 1; /* Allocate one more entry than needed */
75:
76: queue = (void *)kalloc(size * sizeof(commandEntryT));
77: if (!queue)
78: return false;
79:
80: producerLock = IOLockAlloc();
81: if (!producerLock)
82: return false;
83:
84: producerIndex = consumerIndex = 0;
85:
86: return true;
87: }
88:
89: IOCommandQueue *
90: IOCommandQueue::commandQueue(OSObject *inOwner,
91: IOCommandQueueAction inAction,
92: int inSize)
93: {
94: IOCommandQueue *me = new IOCommandQueue;
95:
96: if (me && !me->init(inOwner, inAction, inSize)) {
97: me->free();
98: return 0;
99: }
100:
101: return me;
102: }
103:
104: /*[
105: free
106: - free
107:
108: Mandatory free of the object independent of the current retain count.
109: Returns nil.
110: ]*/
111: void IOCommandQueue::free()
112: {
113: if (queue)
114: kfree((vm_offset_t)queue, size * sizeof(commandEntryT));
115: if (producerSema)
116: semaphore_destroy(kernel_task, producerSema);
117: if (producerLock)
118: IOLockFree(producerLock);
119:
120: super::free();
121: }
122:
123: #if NUM_FIELDS_IN_COMMAND != 4
124: #error IOCommandQueue::checkForWork needs to be updated for new command size
125: #endif
126:
127: bool IOCommandQueue::checkForWork()
128: {
129: void *field0, *field1, *field2, *field3;
130:
131: if (!enabled || consumerIndex == producerIndex)
132: return false;
133:
134: {
135: commandEntryT *q = (commandEntryT *) queue;
136: int localIndex = consumerIndex;
137:
138: field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1];
139: field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3];
140: semaphore_signal(producerSema);
141: }
142:
143: if (++consumerIndex >= size)
144: consumerIndex = 0;
145:
146: IOTimeStampConstant(IODBG_CMDQ(IOCMDQ_ACTION),
147: (unsigned int) action, (unsigned int) owner);
148:
149: (*(IOCommandQueueAction) action)(owner, field0, field1, field2, field3);
150:
151: return (consumerIndex != producerIndex);
152: }
153:
154: /*[
155: enqueueSleep:command:
156: - (kern_return_t) enqueueSleepRaw: (BOOL) gotoSleep
157: field0: (void *) field0 field1: (void *) field1
158: field2: (void *) field2 field3: (void *) field3;
159:
160: Key method that enqueues the four input fields onto the command queue
161: and calls signalWorkAvailable to indicate that work is available to the
162: consumer. This routine is safe against multiple threaded producers.
163:
164: A family of convenience functions have been provided to assist with the
165: enqueueing of an method selector and an integer tag. This relies on the
166: IODevice rawCommandOccurred... command to forward on the requests.
167:
168: See also: signalWorkAvailable, checkForWork
169: ]*/
170: #if NUM_FIELDS_IN_COMMAND != 4
171: #error IOCommandQueue::enqueueCommand needs to be updated
172: #endif
173:
174: kern_return_t
175: IOCommandQueue::enqueueCommand(bool gotoSleep,
176: void *field0, void *field1,
177: void *field2, void *field3)
178: {
179: kern_return_t rtn = KERN_SUCCESS;
180: int retry;
181:
182: /* Make sure there is room in the queue before doing anything else */
183:
184: if (gotoSleep) {
185: retry = 0;
186: do
187: rtn = semaphore_wait(producerSema);
188: while( (KERN_SUCCESS != rtn)
189: && (KERN_OPERATION_TIMED_OUT != rtn)
190: && (KERN_SEMAPHORE_DESTROYED != rtn)
191: && (KERN_TERMINATED != rtn)
192: && ((retry++) < 4));
193: } else
194: rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO);
195:
196: if (KERN_SUCCESS != rtn)
197: return rtn;
198:
199: /* Block other producers */
200: IOTakeLock(producerLock);
201:
202: /*
203: * Make sure that we update the current producer entry before we
204: * increment the producer pointer. This avoids a nasty race as the
205: * as the test for work is producerIndex != consumerIndex and a signal.
206: */
207: {
208: commandEntryT *q = (commandEntryT *) queue;
209: int localIndex = producerIndex;
210:
211: q[localIndex].f[0] = field0; q[localIndex].f[1] = field1;
212: q[localIndex].f[2] = field2; q[localIndex].f[3] = field3;
213: }
214: if (++producerIndex >= size)
215: producerIndex = 0;
216:
217: /* Clear to allow other producers to go now */
218: IOUnlock(producerLock);
219:
220: /*
221: * Right we have created some new work, we had better make sure that
222: * we notify the work loop that it has to test producerIndex.
223: */
224: workLoop->signalWorkAvailable();
225: return rtn;
226: }
227:
228: int IOCommandQueue::performAndFlush(OSObject *target,
229: IOCommandQueueAction inAction)
230: {
231: int numEntries;
232: kern_return_t rtn;
233:
234: // Set the defaults if necessary
235: if (!target)
236: target = owner;
237: if (!inAction)
238: inAction = (IOCommandQueueAction) action;
239:
240: // Lock out the producers first
241: do {
242: rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO);
243: } while (rtn == KERN_SUCCESS);
244:
245: // now step over all remaining entries in the command queue
246: for (numEntries = 0; consumerIndex != producerIndex; ) {
247: void *field0, *field1, *field2, *field3;
248:
249: {
250: commandEntryT *q = (commandEntryT *) queue;
251: int localIndex = consumerIndex;
252:
253: field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1];
254: field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3];
255: }
256:
257: if (++consumerIndex >= size)
258: consumerIndex = 0;
259:
260: (*inAction)(target, field0, field1, field2, field3);
261: }
262:
263: // finally refill the producer semaphore
264: for (int i = 0; i < size; i++)
265: semaphore_signal(producerSema);
266:
267: return numEntries;
268: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.