1e13b1fa5SApple OSS Distributions /*
2e13b1fa5SApple OSS Distributions  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3e13b1fa5SApple OSS Distributions  *
4e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5e13b1fa5SApple OSS Distributions  *
6e13b1fa5SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7e13b1fa5SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8e13b1fa5SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9e13b1fa5SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10e13b1fa5SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11e13b1fa5SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12e13b1fa5SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13e13b1fa5SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14e13b1fa5SApple OSS Distributions  *
15e13b1fa5SApple OSS Distributions  * Please obtain a copy of the License at
16e13b1fa5SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17e13b1fa5SApple OSS Distributions  *
18e13b1fa5SApple OSS Distributions  * The Original Code and all software distributed under the License are
19e13b1fa5SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20e13b1fa5SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21e13b1fa5SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22e13b1fa5SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23e13b1fa5SApple OSS Distributions  * Please see the License for the specific language governing rights and
24e13b1fa5SApple OSS Distributions  * limitations under the License.
25e13b1fa5SApple OSS Distributions  *
26e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27e13b1fa5SApple OSS Distributions  */
28e13b1fa5SApple OSS Distributions 
29e13b1fa5SApple OSS Distributions #include <IOKit/IOSharedDataQueue.h>
30e13b1fa5SApple OSS Distributions #include <IOKit/IODataQueueShared.h>
31e13b1fa5SApple OSS Distributions #include <IOKit/IOLib.h>
32e13b1fa5SApple OSS Distributions #include <IOKit/IOMemoryDescriptor.h>
33e13b1fa5SApple OSS Distributions 
34a3bb9fccSApple OSS Distributions #ifdef enqueue
35a3bb9fccSApple OSS Distributions #undef enqueue
36a3bb9fccSApple OSS Distributions #endif
37a3bb9fccSApple OSS Distributions 
38e13b1fa5SApple OSS Distributions #ifdef dequeue
39e13b1fa5SApple OSS Distributions #undef dequeue
40e13b1fa5SApple OSS Distributions #endif
41e13b1fa5SApple OSS Distributions 
42e13b1fa5SApple OSS Distributions #define super IODataQueue
43e13b1fa5SApple OSS Distributions 
44e13b1fa5SApple OSS Distributions OSDefineMetaClassAndStructors(IOSharedDataQueue, IODataQueue)
45e13b1fa5SApple OSS Distributions 
46e13b1fa5SApple OSS Distributions IOSharedDataQueue *IOSharedDataQueue::withCapacity(UInt32 size)
47e13b1fa5SApple OSS Distributions {
48e13b1fa5SApple OSS Distributions     IOSharedDataQueue *dataQueue = new IOSharedDataQueue;
49e13b1fa5SApple OSS Distributions 
50e13b1fa5SApple OSS Distributions     if (dataQueue) {
51e13b1fa5SApple OSS Distributions         if  (!dataQueue->initWithCapacity(size)) {
52e13b1fa5SApple OSS Distributions             dataQueue->release();
53e13b1fa5SApple OSS Distributions             dataQueue = 0;
54e13b1fa5SApple OSS Distributions         }
55e13b1fa5SApple OSS Distributions     }
56e13b1fa5SApple OSS Distributions 
57e13b1fa5SApple OSS Distributions     return dataQueue;
58e13b1fa5SApple OSS Distributions }
59e13b1fa5SApple OSS Distributions 
60e13b1fa5SApple OSS Distributions IOSharedDataQueue *IOSharedDataQueue::withEntries(UInt32 numEntries, UInt32 entrySize)
61e13b1fa5SApple OSS Distributions {
62e13b1fa5SApple OSS Distributions     IOSharedDataQueue *dataQueue = new IOSharedDataQueue;
63e13b1fa5SApple OSS Distributions 
64e13b1fa5SApple OSS Distributions     if (dataQueue) {
65e13b1fa5SApple OSS Distributions         if (!dataQueue->initWithEntries(numEntries, entrySize)) {
66e13b1fa5SApple OSS Distributions             dataQueue->release();
67e13b1fa5SApple OSS Distributions             dataQueue = 0;
68e13b1fa5SApple OSS Distributions         }
69e13b1fa5SApple OSS Distributions     }
70e13b1fa5SApple OSS Distributions 
71e13b1fa5SApple OSS Distributions     return dataQueue;
72e13b1fa5SApple OSS Distributions }
73e13b1fa5SApple OSS Distributions 
74e13b1fa5SApple OSS Distributions Boolean IOSharedDataQueue::initWithCapacity(UInt32 size)
75e13b1fa5SApple OSS Distributions {
76e13b1fa5SApple OSS Distributions     IODataQueueAppendix *   appendix;
77a3bb9fccSApple OSS Distributions     vm_size_t               allocSize;
78e13b1fa5SApple OSS Distributions 
79e13b1fa5SApple OSS Distributions     if (!super::init()) {
80e13b1fa5SApple OSS Distributions         return false;
81e13b1fa5SApple OSS Distributions     }
82e13b1fa5SApple OSS Distributions 
83a3bb9fccSApple OSS Distributions     _reserved = (ExpansionData *)IOMalloc(sizeof(struct ExpansionData));
84a3bb9fccSApple OSS Distributions     if (!_reserved) {
85a3bb9fccSApple OSS Distributions         return false;
86a3bb9fccSApple OSS Distributions     }
87a3bb9fccSApple OSS Distributions 
88a3bb9fccSApple OSS Distributions     if (size > UINT32_MAX - DATA_QUEUE_MEMORY_HEADER_SIZE - DATA_QUEUE_MEMORY_APPENDIX_SIZE) {
89a3bb9fccSApple OSS Distributions         return false;
90a3bb9fccSApple OSS Distributions     }
91a3bb9fccSApple OSS Distributions 
92a3bb9fccSApple OSS Distributions     allocSize = round_page(size + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE);
93a3bb9fccSApple OSS Distributions 
94a3bb9fccSApple OSS Distributions     if (allocSize < size) {
95a3bb9fccSApple OSS Distributions         return false;
96a3bb9fccSApple OSS Distributions     }
97a3bb9fccSApple OSS Distributions 
98a3bb9fccSApple OSS Distributions     dataQueue = (IODataQueueMemory *)IOMallocAligned(allocSize, PAGE_SIZE);
99e13b1fa5SApple OSS Distributions     if (dataQueue == 0) {
100e13b1fa5SApple OSS Distributions         return false;
101e13b1fa5SApple OSS Distributions     }
1020f3703acSApple OSS Distributions     bzero(dataQueue, allocSize);
103e13b1fa5SApple OSS Distributions 
104e13b1fa5SApple OSS Distributions     dataQueue->queueSize    = size;
1050f3703acSApple OSS Distributions //  dataQueue->head         = 0;
1060f3703acSApple OSS Distributions //  dataQueue->tail         = 0;
107e13b1fa5SApple OSS Distributions 
108a3bb9fccSApple OSS Distributions     if (!setQueueSize(size)) {
109a3bb9fccSApple OSS Distributions         return false;
110a3bb9fccSApple OSS Distributions     }
111a3bb9fccSApple OSS Distributions 
112e13b1fa5SApple OSS Distributions     appendix            = (IODataQueueAppendix *)((UInt8 *)dataQueue + size + DATA_QUEUE_MEMORY_HEADER_SIZE);
113e13b1fa5SApple OSS Distributions     appendix->version   = 0;
1140f3703acSApple OSS Distributions 
1150f3703acSApple OSS Distributions     if (!notifyMsg) {
1160f3703acSApple OSS Distributions         notifyMsg = IOMalloc(sizeof(mach_msg_header_t));
1170f3703acSApple OSS Distributions         if (!notifyMsg)
1180f3703acSApple OSS Distributions             return false;
1190f3703acSApple OSS Distributions     }
1200f3703acSApple OSS Distributions     bzero(notifyMsg, sizeof(mach_msg_header_t));
1210f3703acSApple OSS Distributions 
122e13b1fa5SApple OSS Distributions     setNotificationPort(MACH_PORT_NULL);
123e13b1fa5SApple OSS Distributions 
124e13b1fa5SApple OSS Distributions     return true;
125e13b1fa5SApple OSS Distributions }
126e13b1fa5SApple OSS Distributions 
127e13b1fa5SApple OSS Distributions void IOSharedDataQueue::free()
128e13b1fa5SApple OSS Distributions {
129e13b1fa5SApple OSS Distributions     if (dataQueue) {
130a3bb9fccSApple OSS Distributions         IOFreeAligned(dataQueue, round_page(getQueueSize() + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE));
131e13b1fa5SApple OSS Distributions         dataQueue = NULL;
1320f3703acSApple OSS Distributions         if (notifyMsg) {
1330f3703acSApple OSS Distributions             IOFree(notifyMsg, sizeof(mach_msg_header_t));
1340f3703acSApple OSS Distributions             notifyMsg = NULL;
1350f3703acSApple OSS Distributions         }
136e13b1fa5SApple OSS Distributions     }
137e13b1fa5SApple OSS Distributions 
138a3bb9fccSApple OSS Distributions     if (_reserved) {
139a3bb9fccSApple OSS Distributions         IOFree (_reserved, sizeof(struct ExpansionData));
140a3bb9fccSApple OSS Distributions         _reserved = NULL;
141a3bb9fccSApple OSS Distributions     }
142a3bb9fccSApple OSS Distributions 
143e13b1fa5SApple OSS Distributions     super::free();
144e13b1fa5SApple OSS Distributions }
145e13b1fa5SApple OSS Distributions 
146e13b1fa5SApple OSS Distributions IOMemoryDescriptor *IOSharedDataQueue::getMemoryDescriptor()
147e13b1fa5SApple OSS Distributions {
148e13b1fa5SApple OSS Distributions     IOMemoryDescriptor *descriptor = 0;
149e13b1fa5SApple OSS Distributions 
150e13b1fa5SApple OSS Distributions     if (dataQueue != 0) {
151a3bb9fccSApple OSS Distributions         descriptor = IOMemoryDescriptor::withAddress(dataQueue, getQueueSize() + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE, kIODirectionOutIn);
152e13b1fa5SApple OSS Distributions     }
153e13b1fa5SApple OSS Distributions 
154e13b1fa5SApple OSS Distributions     return descriptor;
155e13b1fa5SApple OSS Distributions }
156e13b1fa5SApple OSS Distributions 
157e13b1fa5SApple OSS Distributions 
158e13b1fa5SApple OSS Distributions IODataQueueEntry * IOSharedDataQueue::peek()
159e13b1fa5SApple OSS Distributions {
160e13b1fa5SApple OSS Distributions     IODataQueueEntry *entry      = 0;
161*88cc0b97SApple OSS Distributions     UInt32            headOffset;
162*88cc0b97SApple OSS Distributions     UInt32            tailOffset;
163e13b1fa5SApple OSS Distributions 
164*88cc0b97SApple OSS Distributions     if (!dataQueue) {
165*88cc0b97SApple OSS Distributions         return NULL;
166*88cc0b97SApple OSS Distributions     }
167*88cc0b97SApple OSS Distributions 
168*88cc0b97SApple OSS Distributions     // Read head and tail with acquire barrier
169*88cc0b97SApple OSS Distributions     headOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_RELAXED);
170*88cc0b97SApple OSS Distributions     tailOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_ACQUIRE);
171*88cc0b97SApple OSS Distributions 
172*88cc0b97SApple OSS Distributions     if (headOffset != tailOffset) {
173e13b1fa5SApple OSS Distributions         IODataQueueEntry *  head        = 0;
174e13b1fa5SApple OSS Distributions         UInt32              headSize    = 0;
175e13b1fa5SApple OSS Distributions         UInt32              headOffset  = dataQueue->head;
176a3bb9fccSApple OSS Distributions         UInt32              queueSize   = getQueueSize();
177a3bb9fccSApple OSS Distributions 
178a3bb9fccSApple OSS Distributions         if (headOffset >= queueSize) {
179a3bb9fccSApple OSS Distributions             return NULL;
180a3bb9fccSApple OSS Distributions         }
181e13b1fa5SApple OSS Distributions 
182e13b1fa5SApple OSS Distributions         head         = (IODataQueueEntry *)((char *)dataQueue->queue + headOffset);
183e13b1fa5SApple OSS Distributions         headSize     = head->size;
184e13b1fa5SApple OSS Distributions 
185e13b1fa5SApple OSS Distributions         // Check if there's enough room before the end of the queue for a header.
186e13b1fa5SApple OSS Distributions         // If there is room, check if there's enough room to hold the header and
187e13b1fa5SApple OSS Distributions         // the data.
188e13b1fa5SApple OSS Distributions 
189a3bb9fccSApple OSS Distributions         if ((headOffset > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) ||
190a3bb9fccSApple OSS Distributions             (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) ||
191a3bb9fccSApple OSS Distributions             (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headSize) ||
192a3bb9fccSApple OSS Distributions             (headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) {
193e13b1fa5SApple OSS Distributions             // No room for the header or the data, wrap to the beginning of the queue.
194a3bb9fccSApple OSS Distributions             // Note: wrapping even with the UINT32_MAX checks, as we have to support
195a3bb9fccSApple OSS Distributions             // queueSize of UINT32_MAX
196e13b1fa5SApple OSS Distributions             entry = dataQueue->queue;
197e13b1fa5SApple OSS Distributions         } else {
198e13b1fa5SApple OSS Distributions             entry = head;
199e13b1fa5SApple OSS Distributions         }
200e13b1fa5SApple OSS Distributions     }
201e13b1fa5SApple OSS Distributions 
202e13b1fa5SApple OSS Distributions     return entry;
203e13b1fa5SApple OSS Distributions }
204e13b1fa5SApple OSS Distributions 
205a3bb9fccSApple OSS Distributions Boolean IOSharedDataQueue::enqueue(void * data, UInt32 dataSize)
206a3bb9fccSApple OSS Distributions {
207*88cc0b97SApple OSS Distributions     UInt32             head;
208*88cc0b97SApple OSS Distributions     UInt32             tail;
209*88cc0b97SApple OSS Distributions     UInt32             newTail;
210a3bb9fccSApple OSS Distributions     const UInt32       entrySize = dataSize + DATA_QUEUE_ENTRY_HEADER_SIZE;
211a3bb9fccSApple OSS Distributions     IODataQueueEntry * entry;
212a3bb9fccSApple OSS Distributions 
213*88cc0b97SApple OSS Distributions     // Force a single read of head and tail
214*88cc0b97SApple OSS Distributions     head = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_RELAXED);
215*88cc0b97SApple OSS Distributions     tail = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_RELAXED);
216*88cc0b97SApple OSS Distributions 
217a3bb9fccSApple OSS Distributions     // Check for overflow of entrySize
218a3bb9fccSApple OSS Distributions     if (dataSize > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) {
219a3bb9fccSApple OSS Distributions         return false;
220a3bb9fccSApple OSS Distributions     }
221a3bb9fccSApple OSS Distributions     // Check for underflow of (getQueueSize() - tail)
2220f3703acSApple OSS Distributions     if (getQueueSize() < tail || getQueueSize() < head) {
223a3bb9fccSApple OSS Distributions         return false;
224a3bb9fccSApple OSS Distributions     }
225a3bb9fccSApple OSS Distributions 
226a3bb9fccSApple OSS Distributions     if ( tail >= head )
227a3bb9fccSApple OSS Distributions     {
228a3bb9fccSApple OSS Distributions         // Is there enough room at the end for the entry?
229a3bb9fccSApple OSS Distributions         if ((entrySize <= UINT32_MAX - tail) &&
230a3bb9fccSApple OSS Distributions             ((tail + entrySize) <= getQueueSize()) )
231a3bb9fccSApple OSS Distributions         {
232a3bb9fccSApple OSS Distributions             entry = (IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail);
233a3bb9fccSApple OSS Distributions 
234a3bb9fccSApple OSS Distributions             entry->size = dataSize;
235a3bb9fccSApple OSS Distributions             memcpy(&entry->data, data, dataSize);
236a3bb9fccSApple OSS Distributions 
237a3bb9fccSApple OSS Distributions             // The tail can be out of bound when the size of the new entry
238a3bb9fccSApple OSS Distributions             // exactly matches the available space at the end of the queue.
239a3bb9fccSApple OSS Distributions             // The tail can range from 0 to dataQueue->queueSize inclusive.
240a3bb9fccSApple OSS Distributions 
241*88cc0b97SApple OSS Distributions             newTail = tail + entrySize;
242a3bb9fccSApple OSS Distributions         }
243a3bb9fccSApple OSS Distributions         else if ( head > entrySize )     // Is there enough room at the beginning?
244a3bb9fccSApple OSS Distributions         {
245a3bb9fccSApple OSS Distributions             // Wrap around to the beginning, but do not allow the tail to catch
246a3bb9fccSApple OSS Distributions             // up to the head.
247a3bb9fccSApple OSS Distributions 
248a3bb9fccSApple OSS Distributions             dataQueue->queue->size = dataSize;
249a3bb9fccSApple OSS Distributions 
250a3bb9fccSApple OSS Distributions             // We need to make sure that there is enough room to set the size before
251a3bb9fccSApple OSS Distributions             // doing this. The user client checks for this and will look for the size
252a3bb9fccSApple OSS Distributions             // at the beginning if there isn't room for it at the end.
253a3bb9fccSApple OSS Distributions 
254a3bb9fccSApple OSS Distributions             if ( ( getQueueSize() - tail ) >= DATA_QUEUE_ENTRY_HEADER_SIZE )
255a3bb9fccSApple OSS Distributions             {
256a3bb9fccSApple OSS Distributions                 ((IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail))->size = dataSize;
257a3bb9fccSApple OSS Distributions             }
258a3bb9fccSApple OSS Distributions 
259a3bb9fccSApple OSS Distributions             memcpy(&dataQueue->queue->data, data, dataSize);
260*88cc0b97SApple OSS Distributions             newTail = entrySize;
261a3bb9fccSApple OSS Distributions         }
262a3bb9fccSApple OSS Distributions         else
263a3bb9fccSApple OSS Distributions         {
264a3bb9fccSApple OSS Distributions             return false;    // queue is full
265a3bb9fccSApple OSS Distributions         }
266a3bb9fccSApple OSS Distributions     }
267a3bb9fccSApple OSS Distributions     else
268a3bb9fccSApple OSS Distributions     {
269a3bb9fccSApple OSS Distributions         // Do not allow the tail to catch up to the head when the queue is full.
270a3bb9fccSApple OSS Distributions         // That's why the comparison uses a '>' rather than '>='.
271a3bb9fccSApple OSS Distributions 
272a3bb9fccSApple OSS Distributions         if ( (head - tail) > entrySize )
273a3bb9fccSApple OSS Distributions         {
274a3bb9fccSApple OSS Distributions             entry = (IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail);
275a3bb9fccSApple OSS Distributions 
276a3bb9fccSApple OSS Distributions             entry->size = dataSize;
277a3bb9fccSApple OSS Distributions             memcpy(&entry->data, data, dataSize);
278*88cc0b97SApple OSS Distributions             newTail = tail + entrySize;
279a3bb9fccSApple OSS Distributions         }
280a3bb9fccSApple OSS Distributions         else
281a3bb9fccSApple OSS Distributions         {
282a3bb9fccSApple OSS Distributions             return false;    // queue is full
283a3bb9fccSApple OSS Distributions         }
284a3bb9fccSApple OSS Distributions     }
285a3bb9fccSApple OSS Distributions 
286*88cc0b97SApple OSS Distributions     // Update tail with release barrier
287*88cc0b97SApple OSS Distributions     __c11_atomic_store((_Atomic UInt32 *)&dataQueue->tail, newTail, __ATOMIC_RELEASE);
288*88cc0b97SApple OSS Distributions 
289a3bb9fccSApple OSS Distributions     // Send notification (via mach message) that data is available.
290a3bb9fccSApple OSS Distributions 
291*88cc0b97SApple OSS Distributions     if ( ( tail == head )                                                   /* queue was empty prior to enqueue() */
292*88cc0b97SApple OSS Distributions       || ( tail == __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_RELAXED) ) )   /* queue was emptied during enqueue() */
293a3bb9fccSApple OSS Distributions     {
294a3bb9fccSApple OSS Distributions         sendDataAvailableNotification();
295a3bb9fccSApple OSS Distributions     }
296a3bb9fccSApple OSS Distributions 
297a3bb9fccSApple OSS Distributions     return true;
298a3bb9fccSApple OSS Distributions }
299a3bb9fccSApple OSS Distributions 
300e13b1fa5SApple OSS Distributions Boolean IOSharedDataQueue::dequeue(void *data, UInt32 *dataSize)
301e13b1fa5SApple OSS Distributions {
302e13b1fa5SApple OSS Distributions     Boolean             retVal          = TRUE;
303e13b1fa5SApple OSS Distributions     IODataQueueEntry *  entry           = 0;
304e13b1fa5SApple OSS Distributions     UInt32              entrySize       = 0;
305*88cc0b97SApple OSS Distributions     UInt32              headOffset      = 0;
306*88cc0b97SApple OSS Distributions     UInt32              tailOffset      = 0;
307e13b1fa5SApple OSS Distributions     UInt32              newHeadOffset   = 0;
308e13b1fa5SApple OSS Distributions 
309*88cc0b97SApple OSS Distributions     if (!dataQueue) {
310*88cc0b97SApple OSS Distributions         return false;
311*88cc0b97SApple OSS Distributions     }
312*88cc0b97SApple OSS Distributions 
313*88cc0b97SApple OSS Distributions     // Read head and tail with acquire barrier
314*88cc0b97SApple OSS Distributions     tailOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_RELAXED);
315*88cc0b97SApple OSS Distributions     headOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_ACQUIRE);
316*88cc0b97SApple OSS Distributions 
317*88cc0b97SApple OSS Distributions     if (headOffset != tailOffset) {
318e13b1fa5SApple OSS Distributions         IODataQueueEntry *  head        = 0;
319e13b1fa5SApple OSS Distributions         UInt32              headSize    = 0;
320a3bb9fccSApple OSS Distributions         UInt32              queueSize   = getQueueSize();
321a3bb9fccSApple OSS Distributions 
322a3bb9fccSApple OSS Distributions         if (headOffset > queueSize) {
323a3bb9fccSApple OSS Distributions             return false;
324a3bb9fccSApple OSS Distributions         }
325e13b1fa5SApple OSS Distributions 
326e13b1fa5SApple OSS Distributions         head         = (IODataQueueEntry *)((char *)dataQueue->queue + headOffset);
327e13b1fa5SApple OSS Distributions         headSize     = head->size;
328e13b1fa5SApple OSS Distributions 
329a3bb9fccSApple OSS Distributions         // we wrapped around to beginning, so read from there
330e13b1fa5SApple OSS Distributions         // either there was not even room for the header
331a3bb9fccSApple OSS Distributions         if ((headOffset > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) ||
332a3bb9fccSApple OSS Distributions             (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) ||
333e13b1fa5SApple OSS Distributions             // or there was room for the header, but not for the data
334a3bb9fccSApple OSS Distributions             (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headSize) ||
335a3bb9fccSApple OSS Distributions             (headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) {
336a3bb9fccSApple OSS Distributions             // Note: we have to wrap to the beginning even with the UINT32_MAX checks
337a3bb9fccSApple OSS Distributions             // because we have to support a queueSize of UINT32_MAX.
338e13b1fa5SApple OSS Distributions             entry           = dataQueue->queue;
339e13b1fa5SApple OSS Distributions             entrySize       = entry->size;
340a3bb9fccSApple OSS Distributions             if ((entrySize > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) ||
341a3bb9fccSApple OSS Distributions                 (entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) {
342a3bb9fccSApple OSS Distributions                 return false;
343a3bb9fccSApple OSS Distributions             }
344e13b1fa5SApple OSS Distributions             newHeadOffset   = entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE;
345e13b1fa5SApple OSS Distributions             // else it is at the end
346e13b1fa5SApple OSS Distributions         } else {
347e13b1fa5SApple OSS Distributions             entry           = head;
348e13b1fa5SApple OSS Distributions             entrySize       = entry->size;
349a3bb9fccSApple OSS Distributions             if ((entrySize > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) ||
350a3bb9fccSApple OSS Distributions                 (entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headOffset) ||
351a3bb9fccSApple OSS Distributions                 (entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE + headOffset > queueSize)) {
352a3bb9fccSApple OSS Distributions                 return false;
353a3bb9fccSApple OSS Distributions             }
354e13b1fa5SApple OSS Distributions             newHeadOffset   = headOffset + entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE;
355e13b1fa5SApple OSS Distributions         }
356e13b1fa5SApple OSS Distributions     }
357e13b1fa5SApple OSS Distributions 
358e13b1fa5SApple OSS Distributions     if (entry) {
359e13b1fa5SApple OSS Distributions         if (data) {
360e13b1fa5SApple OSS Distributions             if (dataSize) {
361e13b1fa5SApple OSS Distributions                 if (entrySize <= *dataSize) {
362e13b1fa5SApple OSS Distributions                     memcpy(data, &(entry->data), entrySize);
363*88cc0b97SApple OSS Distributions                     __c11_atomic_store((_Atomic UInt32 *)&dataQueue->head, newHeadOffset, __ATOMIC_RELEASE);
364e13b1fa5SApple OSS Distributions                 } else {
365e13b1fa5SApple OSS Distributions                     retVal = FALSE;
366e13b1fa5SApple OSS Distributions                 }
367e13b1fa5SApple OSS Distributions             } else {
368e13b1fa5SApple OSS Distributions                 retVal = FALSE;
369e13b1fa5SApple OSS Distributions             }
370e13b1fa5SApple OSS Distributions         } else {
371*88cc0b97SApple OSS Distributions             __c11_atomic_store((_Atomic UInt32 *)&dataQueue->head, newHeadOffset, __ATOMIC_RELEASE);
372e13b1fa5SApple OSS Distributions         }
373e13b1fa5SApple OSS Distributions 
374e13b1fa5SApple OSS Distributions         if (dataSize) {
375e13b1fa5SApple OSS Distributions             *dataSize = entrySize;
376e13b1fa5SApple OSS Distributions         }
377e13b1fa5SApple OSS Distributions     } else {
378e13b1fa5SApple OSS Distributions         retVal = FALSE;
379e13b1fa5SApple OSS Distributions     }
380e13b1fa5SApple OSS Distributions 
381e13b1fa5SApple OSS Distributions     return retVal;
382e13b1fa5SApple OSS Distributions }
383e13b1fa5SApple OSS Distributions 
384a3bb9fccSApple OSS Distributions UInt32 IOSharedDataQueue::getQueueSize()
385a3bb9fccSApple OSS Distributions {
386a3bb9fccSApple OSS Distributions     if (!_reserved) {
387a3bb9fccSApple OSS Distributions         return 0;
388a3bb9fccSApple OSS Distributions     }
389a3bb9fccSApple OSS Distributions     return _reserved->queueSize;
390a3bb9fccSApple OSS Distributions }
391a3bb9fccSApple OSS Distributions 
392a3bb9fccSApple OSS Distributions Boolean IOSharedDataQueue::setQueueSize(UInt32 size)
393a3bb9fccSApple OSS Distributions {
394a3bb9fccSApple OSS Distributions     if (!_reserved) {
395a3bb9fccSApple OSS Distributions         return false;
396a3bb9fccSApple OSS Distributions     }
397a3bb9fccSApple OSS Distributions     _reserved->queueSize = size;
398a3bb9fccSApple OSS Distributions     return true;
399a3bb9fccSApple OSS Distributions }
400e13b1fa5SApple OSS Distributions 
401e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 0);
402e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 1);
403e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 2);
404e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 3);
405e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 4);
406e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 5);
407e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 6);
408e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 7);
409