2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
32 1998-7-13 Godfrey van der Linden(gvdl)
36 #if !defined(__LP64__)
38 #include <IOKit/IOCommandQueue.h>
39 #include <IOKit/IOWorkLoop.h>
40 #include <IOKit/IOTimeStamp.h>
42 #include <mach/sync_policy.h>
45 #define NUM_FIELDS_IN_COMMAND 4
46 typedef struct commandEntryTag
{
47 void *f
[NUM_FIELDS_IN_COMMAND
];
50 #define super IOEventSource
52 OSDefineMetaClassAndStructors(IOCommandQueue
, IOEventSource
)
57 initWithNext:owner:action:size:
58 - initWithNext: (IOEventSource *) inNext
60 action: (SEL) inAction
63 Primary initialiser for the IOCommandQueue class. Returns an
64 IOCommandQueue object that is initialised with the next object in
65 the chain and the owner and action. On return the signalWorkAvailableIMP
66 has been cached for this function.
68 If the object fails to initialise for some reason then [self free] will
69 be called and nil will be returned.
71 See also: initWithNext:owner:action:(IOEventSource)
73 bool IOCommandQueue::init(OSObject
*inOwner
,
74 IOCommandQueueAction inAction
,
77 if ( !super::init(inOwner
, (IOEventSourceAction
) inAction
) )
81 != semaphore_create(kernel_task
, &producerSema
, SYNC_POLICY_FIFO
, inSize
))
84 size
= inSize
+ 1; /* Allocate one more entry than needed */
86 queue
= (void *)kalloc(size
* sizeof(commandEntryT
));
90 producerLock
= IOLockAlloc();
94 producerIndex
= consumerIndex
= 0;
100 IOCommandQueue::commandQueue(OSObject
*inOwner
,
101 IOCommandQueueAction inAction
,
104 IOCommandQueue
*me
= new IOCommandQueue
;
106 if (me
&& !me
->init(inOwner
, inAction
, inSize
)) {
118 Mandatory free of the object independent of the current retain count.
121 void IOCommandQueue::free()
124 kfree(queue
, size
* sizeof(commandEntryT
));
126 semaphore_destroy(kernel_task
, producerSema
);
128 IOLockFree(producerLock
);
133 #if NUM_FIELDS_IN_COMMAND != 4
134 #error IOCommandQueue::checkForWork needs to be updated for new command size
137 bool IOCommandQueue::checkForWork()
139 void *field0
, *field1
, *field2
, *field3
;
141 if (!enabled
|| consumerIndex
== producerIndex
)
145 commandEntryT
*q
= (commandEntryT
*) queue
;
146 int localIndex
= consumerIndex
;
148 field0
= q
[localIndex
].f
[0]; field1
= q
[localIndex
].f
[1];
149 field2
= q
[localIndex
].f
[2]; field3
= q
[localIndex
].f
[3];
150 semaphore_signal(producerSema
);
153 if (++consumerIndex
>= size
)
156 IOTimeStampConstant(IODBG_CMDQ(IOCMDQ_ACTION
),
157 (uintptr_t) action
, (uintptr_t) owner
);
159 (*(IOCommandQueueAction
) action
)(owner
, field0
, field1
, field2
, field3
);
161 return (consumerIndex
!= producerIndex
);
165 enqueueSleep:command:
166 - (kern_return_t) enqueueSleepRaw: (BOOL) gotoSleep
167 field0: (void *) field0 field1: (void *) field1
168 field2: (void *) field2 field3: (void *) field3;
170 Key method that enqueues the four input fields onto the command queue
171 and calls signalWorkAvailable to indicate that work is available to the
172 consumer. This routine is safe against multiple threaded producers.
174 A family of convenience functions have been provided to assist with the
175 enqueueing of an method selector and an integer tag. This relies on the
176 IODevice rawCommandOccurred... command to forward on the requests.
178 See also: signalWorkAvailable, checkForWork
180 #if NUM_FIELDS_IN_COMMAND != 4
181 #error IOCommandQueue::enqueueCommand needs to be updated
185 IOCommandQueue::enqueueCommand(bool gotoSleep
,
186 void *field0
, void *field1
,
187 void *field2
, void *field3
)
189 kern_return_t rtn
= KERN_SUCCESS
;
192 /* Make sure there is room in the queue before doing anything else */
197 rtn
= semaphore_wait(producerSema
);
198 while( (KERN_SUCCESS
!= rtn
)
199 && (KERN_OPERATION_TIMED_OUT
!= rtn
)
200 && (KERN_SEMAPHORE_DESTROYED
!= rtn
)
201 && (KERN_TERMINATED
!= rtn
)
204 rtn
= semaphore_timedwait(producerSema
, MACH_TIMESPEC_ZERO
);
206 if (KERN_SUCCESS
!= rtn
)
209 /* Block other producers */
210 IOTakeLock(producerLock
);
213 * Make sure that we update the current producer entry before we
214 * increment the producer pointer. This avoids a nasty race as the
215 * as the test for work is producerIndex != consumerIndex and a signal.
218 commandEntryT
*q
= (commandEntryT
*) queue
;
219 int localIndex
= producerIndex
;
221 q
[localIndex
].f
[0] = field0
; q
[localIndex
].f
[1] = field1
;
222 q
[localIndex
].f
[2] = field2
; q
[localIndex
].f
[3] = field3
;
224 if (++producerIndex
>= size
)
227 /* Clear to allow other producers to go now */
228 IOUnlock(producerLock
);
231 * Right we have created some new work, we had better make sure that
232 * we notify the work loop that it has to test producerIndex.
234 signalWorkAvailable();
238 int IOCommandQueue::performAndFlush(OSObject
*target
,
239 IOCommandQueueAction inAction
)
244 // Set the defaults if necessary
248 inAction
= (IOCommandQueueAction
) action
;
250 // Lock out the producers first
252 rtn
= semaphore_timedwait(producerSema
, MACH_TIMESPEC_ZERO
);
253 } while (rtn
== KERN_SUCCESS
);
255 // now step over all remaining entries in the command queue
256 for (numEntries
= 0; consumerIndex
!= producerIndex
; ) {
257 void *field0
, *field1
, *field2
, *field3
;
260 commandEntryT
*q
= (commandEntryT
*) queue
;
261 int localIndex
= consumerIndex
;
263 field0
= q
[localIndex
].f
[0]; field1
= q
[localIndex
].f
[1];
264 field2
= q
[localIndex
].f
[2]; field3
= q
[localIndex
].f
[3];
267 if (++consumerIndex
>= size
)
270 (*inAction
)(target
, field0
, field1
, field2
, field3
);
273 // finally refill the producer semaphore to size - 1
274 for (int i
= 1; i
< size
; i
++)
275 semaphore_signal(producerSema
);
280 #endif /* !defined(__LP64__) */