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(); 53*a5e72196SApple OSS Distributions dataQueue = NULL; 54e13b1fa5SApple OSS Distributions } 55e13b1fa5SApple OSS Distributions } 56e13b1fa5SApple OSS Distributions 57e13b1fa5SApple OSS Distributions return dataQueue; 58e13b1fa5SApple OSS Distributions } 59e13b1fa5SApple OSS Distributions 60*a5e72196SApple OSS Distributions IOSharedDataQueue * 61*a5e72196SApple OSS Distributions IOSharedDataQueue::withEntries(UInt32 numEntries, UInt32 entrySize) 62e13b1fa5SApple OSS Distributions { 63e13b1fa5SApple OSS Distributions IOSharedDataQueue *dataQueue = new IOSharedDataQueue; 64e13b1fa5SApple OSS Distributions 65e13b1fa5SApple OSS Distributions if (dataQueue) { 66e13b1fa5SApple OSS Distributions if (!dataQueue->initWithEntries(numEntries, entrySize)) { 67e13b1fa5SApple OSS Distributions dataQueue->release(); 68*a5e72196SApple OSS Distributions dataQueue = NULL; 69e13b1fa5SApple OSS Distributions } 70e13b1fa5SApple OSS Distributions } 71e13b1fa5SApple OSS Distributions 72e13b1fa5SApple OSS Distributions return dataQueue; 73e13b1fa5SApple OSS Distributions } 74e13b1fa5SApple OSS Distributions 75*a5e72196SApple OSS Distributions Boolean 76*a5e72196SApple OSS Distributions IOSharedDataQueue::initWithCapacity(UInt32 size) 77e13b1fa5SApple OSS Distributions { 78e13b1fa5SApple OSS Distributions IODataQueueAppendix * appendix; 79a3bb9fccSApple OSS Distributions vm_size_t allocSize; 80e13b1fa5SApple OSS Distributions 81e13b1fa5SApple OSS Distributions if (!super::init()) { 82e13b1fa5SApple OSS Distributions return false; 83e13b1fa5SApple OSS Distributions } 84e13b1fa5SApple OSS Distributions 85a3bb9fccSApple OSS Distributions _reserved = (ExpansionData *)IOMalloc(sizeof(struct ExpansionData)); 86a3bb9fccSApple OSS Distributions if (!_reserved) { 87a3bb9fccSApple OSS Distributions return false; 88a3bb9fccSApple OSS Distributions } 89a3bb9fccSApple OSS Distributions 90a3bb9fccSApple OSS Distributions if (size > UINT32_MAX - DATA_QUEUE_MEMORY_HEADER_SIZE - DATA_QUEUE_MEMORY_APPENDIX_SIZE) { 91a3bb9fccSApple OSS Distributions return false; 92a3bb9fccSApple OSS Distributions } 93a3bb9fccSApple OSS Distributions 94a3bb9fccSApple OSS Distributions allocSize = round_page(size + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE); 95a3bb9fccSApple OSS Distributions 96a3bb9fccSApple OSS Distributions if (allocSize < size) { 97a3bb9fccSApple OSS Distributions return false; 98a3bb9fccSApple OSS Distributions } 99a3bb9fccSApple OSS Distributions 100a3bb9fccSApple OSS Distributions dataQueue = (IODataQueueMemory *)IOMallocAligned(allocSize, PAGE_SIZE); 101*a5e72196SApple OSS Distributions if (dataQueue == NULL) { 102e13b1fa5SApple OSS Distributions return false; 103e13b1fa5SApple OSS Distributions } 1040f3703acSApple OSS Distributions bzero(dataQueue, allocSize); 105e13b1fa5SApple OSS Distributions 106e13b1fa5SApple OSS Distributions dataQueue->queueSize = size; 1070f3703acSApple OSS Distributions // dataQueue->head = 0; 1080f3703acSApple OSS Distributions // dataQueue->tail = 0; 109e13b1fa5SApple OSS Distributions 110a3bb9fccSApple OSS Distributions if (!setQueueSize(size)) { 111a3bb9fccSApple OSS Distributions return false; 112a3bb9fccSApple OSS Distributions } 113a3bb9fccSApple OSS Distributions 114e13b1fa5SApple OSS Distributions appendix = (IODataQueueAppendix *)((UInt8 *)dataQueue + size + DATA_QUEUE_MEMORY_HEADER_SIZE); 115e13b1fa5SApple OSS Distributions appendix->version = 0; 1160f3703acSApple OSS Distributions 1170f3703acSApple OSS Distributions if (!notifyMsg) { 1180f3703acSApple OSS Distributions notifyMsg = IOMalloc(sizeof(mach_msg_header_t)); 119*a5e72196SApple OSS Distributions if (!notifyMsg) { 1200f3703acSApple OSS Distributions return false; 1210f3703acSApple OSS Distributions } 122*a5e72196SApple OSS Distributions } 1230f3703acSApple OSS Distributions bzero(notifyMsg, sizeof(mach_msg_header_t)); 1240f3703acSApple OSS Distributions 125e13b1fa5SApple OSS Distributions setNotificationPort(MACH_PORT_NULL); 126e13b1fa5SApple OSS Distributions 127e13b1fa5SApple OSS Distributions return true; 128e13b1fa5SApple OSS Distributions } 129e13b1fa5SApple OSS Distributions 130*a5e72196SApple OSS Distributions void 131*a5e72196SApple OSS Distributions IOSharedDataQueue::free() 132e13b1fa5SApple OSS Distributions { 133e13b1fa5SApple OSS Distributions if (dataQueue) { 134a3bb9fccSApple OSS Distributions IOFreeAligned(dataQueue, round_page(getQueueSize() + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE)); 135e13b1fa5SApple OSS Distributions dataQueue = NULL; 1360f3703acSApple OSS Distributions if (notifyMsg) { 1370f3703acSApple OSS Distributions IOFree(notifyMsg, sizeof(mach_msg_header_t)); 1380f3703acSApple OSS Distributions notifyMsg = NULL; 1390f3703acSApple OSS Distributions } 140e13b1fa5SApple OSS Distributions } 141e13b1fa5SApple OSS Distributions 142a3bb9fccSApple OSS Distributions if (_reserved) { 143a3bb9fccSApple OSS Distributions IOFree(_reserved, sizeof(struct ExpansionData)); 144a3bb9fccSApple OSS Distributions _reserved = NULL; 145a3bb9fccSApple OSS Distributions } 146a3bb9fccSApple OSS Distributions 147e13b1fa5SApple OSS Distributions super::free(); 148e13b1fa5SApple OSS Distributions } 149e13b1fa5SApple OSS Distributions 150*a5e72196SApple OSS Distributions IOMemoryDescriptor * 151*a5e72196SApple OSS Distributions IOSharedDataQueue::getMemoryDescriptor() 152e13b1fa5SApple OSS Distributions { 153*a5e72196SApple OSS Distributions IOMemoryDescriptor *descriptor = NULL; 154e13b1fa5SApple OSS Distributions 155*a5e72196SApple OSS Distributions if (dataQueue != NULL) { 156a3bb9fccSApple OSS Distributions descriptor = IOMemoryDescriptor::withAddress(dataQueue, getQueueSize() + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE, kIODirectionOutIn); 157e13b1fa5SApple OSS Distributions } 158e13b1fa5SApple OSS Distributions 159e13b1fa5SApple OSS Distributions return descriptor; 160e13b1fa5SApple OSS Distributions } 161e13b1fa5SApple OSS Distributions 162e13b1fa5SApple OSS Distributions 163*a5e72196SApple OSS Distributions IODataQueueEntry * 164*a5e72196SApple OSS Distributions IOSharedDataQueue::peek() 165e13b1fa5SApple OSS Distributions { 166*a5e72196SApple OSS Distributions IODataQueueEntry *entry = NULL; 16788cc0b97SApple OSS Distributions UInt32 headOffset; 16888cc0b97SApple OSS Distributions UInt32 tailOffset; 169e13b1fa5SApple OSS Distributions 17088cc0b97SApple OSS Distributions if (!dataQueue) { 17188cc0b97SApple OSS Distributions return NULL; 17288cc0b97SApple OSS Distributions } 17388cc0b97SApple OSS Distributions 17488cc0b97SApple OSS Distributions // Read head and tail with acquire barrier 175cc9a6355SApple OSS Distributions // See rdar://problem/40780584 for an explanation of relaxed/acquire barriers 17688cc0b97SApple OSS Distributions headOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_RELAXED); 17788cc0b97SApple OSS Distributions tailOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_ACQUIRE); 17888cc0b97SApple OSS Distributions 17988cc0b97SApple OSS Distributions if (headOffset != tailOffset) { 180*a5e72196SApple OSS Distributions volatile IODataQueueEntry * head = NULL; 181e13b1fa5SApple OSS Distributions UInt32 headSize = 0; 182e13b1fa5SApple OSS Distributions UInt32 headOffset = dataQueue->head; 183a3bb9fccSApple OSS Distributions UInt32 queueSize = getQueueSize(); 184a3bb9fccSApple OSS Distributions 185a3bb9fccSApple OSS Distributions if (headOffset >= queueSize) { 186a3bb9fccSApple OSS Distributions return NULL; 187a3bb9fccSApple OSS Distributions } 188e13b1fa5SApple OSS Distributions 189e13b1fa5SApple OSS Distributions head = (IODataQueueEntry *)((char *)dataQueue->queue + headOffset); 190e13b1fa5SApple OSS Distributions headSize = head->size; 191e13b1fa5SApple OSS Distributions 192e13b1fa5SApple OSS Distributions // Check if there's enough room before the end of the queue for a header. 193e13b1fa5SApple OSS Distributions // If there is room, check if there's enough room to hold the header and 194e13b1fa5SApple OSS Distributions // the data. 195e13b1fa5SApple OSS Distributions 196a3bb9fccSApple OSS Distributions if ((headOffset > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) || 197a3bb9fccSApple OSS Distributions (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) || 198a3bb9fccSApple OSS Distributions (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headSize) || 199a3bb9fccSApple OSS Distributions (headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) { 200e13b1fa5SApple OSS Distributions // No room for the header or the data, wrap to the beginning of the queue. 201a3bb9fccSApple OSS Distributions // Note: wrapping even with the UINT32_MAX checks, as we have to support 202a3bb9fccSApple OSS Distributions // queueSize of UINT32_MAX 203e13b1fa5SApple OSS Distributions entry = dataQueue->queue; 204e13b1fa5SApple OSS Distributions } else { 205*a5e72196SApple OSS Distributions entry = (IODataQueueEntry *)head; 206e13b1fa5SApple OSS Distributions } 207e13b1fa5SApple OSS Distributions } 208e13b1fa5SApple OSS Distributions 209e13b1fa5SApple OSS Distributions return entry; 210e13b1fa5SApple OSS Distributions } 211e13b1fa5SApple OSS Distributions 212*a5e72196SApple OSS Distributions Boolean 213*a5e72196SApple OSS Distributions IOSharedDataQueue::enqueue(void * data, UInt32 dataSize) 214a3bb9fccSApple OSS Distributions { 21588cc0b97SApple OSS Distributions UInt32 head; 21688cc0b97SApple OSS Distributions UInt32 tail; 21788cc0b97SApple OSS Distributions UInt32 newTail; 218a3bb9fccSApple OSS Distributions const UInt32 entrySize = dataSize + DATA_QUEUE_ENTRY_HEADER_SIZE; 219a3bb9fccSApple OSS Distributions IODataQueueEntry * entry; 220a3bb9fccSApple OSS Distributions 22188cc0b97SApple OSS Distributions // Force a single read of head and tail 222cc9a6355SApple OSS Distributions // See rdar://problem/40780584 for an explanation of relaxed/acquire barriers 22388cc0b97SApple OSS Distributions tail = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_RELAXED); 224cc9a6355SApple OSS Distributions head = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_ACQUIRE); 22588cc0b97SApple OSS Distributions 226a3bb9fccSApple OSS Distributions // Check for overflow of entrySize 227a3bb9fccSApple OSS Distributions if (dataSize > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) { 228a3bb9fccSApple OSS Distributions return false; 229a3bb9fccSApple OSS Distributions } 230a3bb9fccSApple OSS Distributions // Check for underflow of (getQueueSize() - tail) 2310f3703acSApple OSS Distributions if (getQueueSize() < tail || getQueueSize() < head) { 232a3bb9fccSApple OSS Distributions return false; 233a3bb9fccSApple OSS Distributions } 234a3bb9fccSApple OSS Distributions 235*a5e72196SApple OSS Distributions if (tail >= head) { 236a3bb9fccSApple OSS Distributions // Is there enough room at the end for the entry? 237a3bb9fccSApple OSS Distributions if ((entrySize <= UINT32_MAX - tail) && 238*a5e72196SApple OSS Distributions ((tail + entrySize) <= getQueueSize())) { 239a3bb9fccSApple OSS Distributions entry = (IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail); 240a3bb9fccSApple OSS Distributions 241a3bb9fccSApple OSS Distributions entry->size = dataSize; 242*a5e72196SApple OSS Distributions __nochk_memcpy(&entry->data, data, dataSize); 243a3bb9fccSApple OSS Distributions 244a3bb9fccSApple OSS Distributions // The tail can be out of bound when the size of the new entry 245a3bb9fccSApple OSS Distributions // exactly matches the available space at the end of the queue. 246a3bb9fccSApple OSS Distributions // The tail can range from 0 to dataQueue->queueSize inclusive. 247a3bb9fccSApple OSS Distributions 24888cc0b97SApple OSS Distributions newTail = tail + entrySize; 249*a5e72196SApple OSS Distributions } else if (head > entrySize) { // Is there enough room at the beginning? 250a3bb9fccSApple OSS Distributions // Wrap around to the beginning, but do not allow the tail to catch 251a3bb9fccSApple OSS Distributions // up to the head. 252a3bb9fccSApple OSS Distributions 253a3bb9fccSApple OSS Distributions dataQueue->queue->size = dataSize; 254a3bb9fccSApple OSS Distributions 255a3bb9fccSApple OSS Distributions // We need to make sure that there is enough room to set the size before 256a3bb9fccSApple OSS Distributions // doing this. The user client checks for this and will look for the size 257a3bb9fccSApple OSS Distributions // at the beginning if there isn't room for it at the end. 258a3bb9fccSApple OSS Distributions 259*a5e72196SApple OSS Distributions if ((getQueueSize() - tail) >= DATA_QUEUE_ENTRY_HEADER_SIZE) { 260a3bb9fccSApple OSS Distributions ((IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail))->size = dataSize; 261a3bb9fccSApple OSS Distributions } 262a3bb9fccSApple OSS Distributions 263*a5e72196SApple OSS Distributions __nochk_memcpy(&dataQueue->queue->data, data, dataSize); 26488cc0b97SApple OSS Distributions newTail = entrySize; 265*a5e72196SApple OSS Distributions } else { 266a3bb9fccSApple OSS Distributions return false; // queue is full 267a3bb9fccSApple OSS Distributions } 268*a5e72196SApple OSS Distributions } else { 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 272*a5e72196SApple OSS Distributions if ((head - tail) > entrySize) { 273a3bb9fccSApple OSS Distributions entry = (IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail); 274a3bb9fccSApple OSS Distributions 275a3bb9fccSApple OSS Distributions entry->size = dataSize; 276*a5e72196SApple OSS Distributions __nochk_memcpy(&entry->data, data, dataSize); 27788cc0b97SApple OSS Distributions newTail = tail + entrySize; 278*a5e72196SApple OSS Distributions } else { 279a3bb9fccSApple OSS Distributions return false; // queue is full 280a3bb9fccSApple OSS Distributions } 281a3bb9fccSApple OSS Distributions } 282a3bb9fccSApple OSS Distributions 283cc9a6355SApple OSS Distributions // Publish the data we just enqueued 28488cc0b97SApple OSS Distributions __c11_atomic_store((_Atomic UInt32 *)&dataQueue->tail, newTail, __ATOMIC_RELEASE); 28588cc0b97SApple OSS Distributions 286cc9a6355SApple OSS Distributions if (tail != head) { 287cc9a6355SApple OSS Distributions // 288cc9a6355SApple OSS Distributions // The memory barrier below paris with the one in ::dequeue 289cc9a6355SApple OSS Distributions // so that either our store to the tail cannot be missed by 290cc9a6355SApple OSS Distributions // the next dequeue attempt, or we will observe the dequeuer 291cc9a6355SApple OSS Distributions // making the queue empty. 292cc9a6355SApple OSS Distributions // 293cc9a6355SApple OSS Distributions // Of course, if we already think the queue is empty, 294cc9a6355SApple OSS Distributions // there's no point paying this extra cost. 295cc9a6355SApple OSS Distributions // 296cc9a6355SApple OSS Distributions __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); 297cc9a6355SApple OSS Distributions head = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_RELAXED); 298a3bb9fccSApple OSS Distributions } 299a3bb9fccSApple OSS Distributions 300cc9a6355SApple OSS Distributions if (tail == head) { 301cc9a6355SApple OSS Distributions // Send notification (via mach message) that data is now available. 302cc9a6355SApple OSS Distributions sendDataAvailableNotification(); 303cc9a6355SApple OSS Distributions } 304a3bb9fccSApple OSS Distributions return true; 305a3bb9fccSApple OSS Distributions } 306a3bb9fccSApple OSS Distributions 307*a5e72196SApple OSS Distributions Boolean 308*a5e72196SApple OSS Distributions IOSharedDataQueue::dequeue(void *data, UInt32 *dataSize) 309e13b1fa5SApple OSS Distributions { 310e13b1fa5SApple OSS Distributions Boolean retVal = TRUE; 311*a5e72196SApple OSS Distributions volatile IODataQueueEntry * entry = NULL; 312e13b1fa5SApple OSS Distributions UInt32 entrySize = 0; 31388cc0b97SApple OSS Distributions UInt32 headOffset = 0; 31488cc0b97SApple OSS Distributions UInt32 tailOffset = 0; 315e13b1fa5SApple OSS Distributions UInt32 newHeadOffset = 0; 316e13b1fa5SApple OSS Distributions 317cc9a6355SApple OSS Distributions if (!dataQueue || (data && !dataSize)) { 31888cc0b97SApple OSS Distributions return false; 31988cc0b97SApple OSS Distributions } 32088cc0b97SApple OSS Distributions 32188cc0b97SApple OSS Distributions // Read head and tail with acquire barrier 322cc9a6355SApple OSS Distributions // See rdar://problem/40780584 for an explanation of relaxed/acquire barriers 323cc9a6355SApple OSS Distributions headOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_RELAXED); 324cc9a6355SApple OSS Distributions tailOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_ACQUIRE); 32588cc0b97SApple OSS Distributions 32688cc0b97SApple OSS Distributions if (headOffset != tailOffset) { 327*a5e72196SApple OSS Distributions volatile IODataQueueEntry * head = NULL; 328e13b1fa5SApple OSS Distributions UInt32 headSize = 0; 329a3bb9fccSApple OSS Distributions UInt32 queueSize = getQueueSize(); 330a3bb9fccSApple OSS Distributions 331a3bb9fccSApple OSS Distributions if (headOffset > queueSize) { 332a3bb9fccSApple OSS Distributions return false; 333a3bb9fccSApple OSS Distributions } 334e13b1fa5SApple OSS Distributions 335e13b1fa5SApple OSS Distributions head = (IODataQueueEntry *)((char *)dataQueue->queue + headOffset); 336e13b1fa5SApple OSS Distributions headSize = head->size; 337e13b1fa5SApple OSS Distributions 338a3bb9fccSApple OSS Distributions // we wrapped around to beginning, so read from there 339e13b1fa5SApple OSS Distributions // either there was not even room for the header 340a3bb9fccSApple OSS Distributions if ((headOffset > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) || 341a3bb9fccSApple OSS Distributions (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) || 342e13b1fa5SApple OSS Distributions // or there was room for the header, but not for the data 343a3bb9fccSApple OSS Distributions (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headSize) || 344a3bb9fccSApple OSS Distributions (headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) { 345a3bb9fccSApple OSS Distributions // Note: we have to wrap to the beginning even with the UINT32_MAX checks 346a3bb9fccSApple OSS Distributions // because we have to support a queueSize of UINT32_MAX. 347e13b1fa5SApple OSS Distributions entry = dataQueue->queue; 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 > queueSize)) { 351a3bb9fccSApple OSS Distributions return false; 352a3bb9fccSApple OSS Distributions } 353e13b1fa5SApple OSS Distributions newHeadOffset = entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE; 354e13b1fa5SApple OSS Distributions // else it is at the end 355e13b1fa5SApple OSS Distributions } else { 356e13b1fa5SApple OSS Distributions entry = head; 357e13b1fa5SApple OSS Distributions entrySize = entry->size; 358a3bb9fccSApple OSS Distributions if ((entrySize > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) || 359a3bb9fccSApple OSS Distributions (entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headOffset) || 360a3bb9fccSApple OSS Distributions (entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE + headOffset > queueSize)) { 361a3bb9fccSApple OSS Distributions return false; 362a3bb9fccSApple OSS Distributions } 363e13b1fa5SApple OSS Distributions newHeadOffset = headOffset + entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE; 364e13b1fa5SApple OSS Distributions } 365cc9a6355SApple OSS Distributions } else { 366cc9a6355SApple OSS Distributions // empty queue 367cc9a6355SApple OSS Distributions return false; 368e13b1fa5SApple OSS Distributions } 369e13b1fa5SApple OSS Distributions 370e13b1fa5SApple OSS Distributions if (data) { 371cc9a6355SApple OSS Distributions if (entrySize > *dataSize) { 372cc9a6355SApple OSS Distributions // not enough space 373cc9a6355SApple OSS Distributions return false; 374cc9a6355SApple OSS Distributions } 375*a5e72196SApple OSS Distributions __nochk_memcpy(data, (void *)entry->data, entrySize); 376e13b1fa5SApple OSS Distributions *dataSize = entrySize; 377e13b1fa5SApple OSS Distributions } 378cc9a6355SApple OSS Distributions 379cc9a6355SApple OSS Distributions __c11_atomic_store((_Atomic UInt32 *)&dataQueue->head, newHeadOffset, __ATOMIC_RELEASE); 380cc9a6355SApple OSS Distributions 381cc9a6355SApple OSS Distributions if (newHeadOffset == tailOffset) { 382cc9a6355SApple OSS Distributions // 383cc9a6355SApple OSS Distributions // If we are making the queue empty, then we need to make sure 384cc9a6355SApple OSS Distributions // that either the enqueuer notices, or we notice the enqueue 385cc9a6355SApple OSS Distributions // that raced with our making of the queue empty. 386cc9a6355SApple OSS Distributions // 387cc9a6355SApple OSS Distributions __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); 388e13b1fa5SApple OSS Distributions } 389e13b1fa5SApple OSS Distributions 390e13b1fa5SApple OSS Distributions return retVal; 391e13b1fa5SApple OSS Distributions } 392e13b1fa5SApple OSS Distributions 393*a5e72196SApple OSS Distributions UInt32 394*a5e72196SApple OSS Distributions IOSharedDataQueue::getQueueSize() 395a3bb9fccSApple OSS Distributions { 396a3bb9fccSApple OSS Distributions if (!_reserved) { 397a3bb9fccSApple OSS Distributions return 0; 398a3bb9fccSApple OSS Distributions } 399a3bb9fccSApple OSS Distributions return _reserved->queueSize; 400a3bb9fccSApple OSS Distributions } 401a3bb9fccSApple OSS Distributions 402*a5e72196SApple OSS Distributions Boolean 403*a5e72196SApple OSS Distributions IOSharedDataQueue::setQueueSize(UInt32 size) 404a3bb9fccSApple OSS Distributions { 405a3bb9fccSApple OSS Distributions if (!_reserved) { 406a3bb9fccSApple OSS Distributions return false; 407a3bb9fccSApple OSS Distributions } 408a3bb9fccSApple OSS Distributions _reserved->queueSize = size; 409a3bb9fccSApple OSS Distributions return true; 410a3bb9fccSApple OSS Distributions } 411e13b1fa5SApple OSS Distributions 412e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 0); 413e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 1); 414e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 2); 415e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 3); 416e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 4); 417e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 5); 418e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 6); 419e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 7); 420