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 29*bb611c8fSApple OSS Distributions #define IOKIT_ENABLE_SHARED_PTR 30*bb611c8fSApple OSS Distributions 31e13b1fa5SApple OSS Distributions #include <IOKit/IOSharedDataQueue.h> 32e13b1fa5SApple OSS Distributions #include <IOKit/IODataQueueShared.h> 33e13b1fa5SApple OSS Distributions #include <IOKit/IOLib.h> 34e13b1fa5SApple OSS Distributions #include <IOKit/IOMemoryDescriptor.h> 35*bb611c8fSApple OSS Distributions #include <libkern/c++/OSSharedPtr.h> 36e13b1fa5SApple OSS Distributions 37a3bb9fccSApple OSS Distributions #ifdef enqueue 38a3bb9fccSApple OSS Distributions #undef enqueue 39a3bb9fccSApple OSS Distributions #endif 40a3bb9fccSApple OSS Distributions 41e13b1fa5SApple OSS Distributions #ifdef dequeue 42e13b1fa5SApple OSS Distributions #undef dequeue 43e13b1fa5SApple OSS Distributions #endif 44e13b1fa5SApple OSS Distributions 45e13b1fa5SApple OSS Distributions #define super IODataQueue 46e13b1fa5SApple OSS Distributions 47e13b1fa5SApple OSS Distributions OSDefineMetaClassAndStructors(IOSharedDataQueue, IODataQueue) 48e13b1fa5SApple OSS Distributions 49*bb611c8fSApple OSS Distributions OSSharedPtr<IOSharedDataQueue> 50*bb611c8fSApple OSS Distributions IOSharedDataQueue::withCapacity(UInt32 size) 51e13b1fa5SApple OSS Distributions { 52*bb611c8fSApple OSS Distributions OSSharedPtr<IOSharedDataQueue> dataQueue = OSMakeShared<IOSharedDataQueue>(); 53e13b1fa5SApple OSS Distributions 54e13b1fa5SApple OSS Distributions if (dataQueue) { 55e13b1fa5SApple OSS Distributions if (!dataQueue->initWithCapacity(size)) { 56*bb611c8fSApple OSS Distributions return nullptr; 57e13b1fa5SApple OSS Distributions } 58e13b1fa5SApple OSS Distributions } 59e13b1fa5SApple OSS Distributions 60e13b1fa5SApple OSS Distributions return dataQueue; 61e13b1fa5SApple OSS Distributions } 62e13b1fa5SApple OSS Distributions 63*bb611c8fSApple OSS Distributions OSSharedPtr<IOSharedDataQueue> 64a5e72196SApple OSS Distributions IOSharedDataQueue::withEntries(UInt32 numEntries, UInt32 entrySize) 65e13b1fa5SApple OSS Distributions { 66*bb611c8fSApple OSS Distributions OSSharedPtr<IOSharedDataQueue> dataQueue = OSMakeShared<IOSharedDataQueue>(); 67e13b1fa5SApple OSS Distributions 68e13b1fa5SApple OSS Distributions if (dataQueue) { 69e13b1fa5SApple OSS Distributions if (!dataQueue->initWithEntries(numEntries, entrySize)) { 70*bb611c8fSApple OSS Distributions return nullptr; 71e13b1fa5SApple OSS Distributions } 72e13b1fa5SApple OSS Distributions } 73e13b1fa5SApple OSS Distributions 74e13b1fa5SApple OSS Distributions return dataQueue; 75e13b1fa5SApple OSS Distributions } 76e13b1fa5SApple OSS Distributions 77a5e72196SApple OSS Distributions Boolean 78a5e72196SApple OSS Distributions IOSharedDataQueue::initWithCapacity(UInt32 size) 79e13b1fa5SApple OSS Distributions { 80e13b1fa5SApple OSS Distributions IODataQueueAppendix * appendix; 81a3bb9fccSApple OSS Distributions vm_size_t allocSize; 82e13b1fa5SApple OSS Distributions 83e13b1fa5SApple OSS Distributions if (!super::init()) { 84e13b1fa5SApple OSS Distributions return false; 85e13b1fa5SApple OSS Distributions } 86e13b1fa5SApple OSS Distributions 87a3bb9fccSApple OSS Distributions _reserved = (ExpansionData *)IOMalloc(sizeof(struct ExpansionData)); 88a3bb9fccSApple OSS Distributions if (!_reserved) { 89a3bb9fccSApple OSS Distributions return false; 90a3bb9fccSApple OSS Distributions } 91a3bb9fccSApple OSS Distributions 92a3bb9fccSApple OSS Distributions if (size > UINT32_MAX - DATA_QUEUE_MEMORY_HEADER_SIZE - DATA_QUEUE_MEMORY_APPENDIX_SIZE) { 93a3bb9fccSApple OSS Distributions return false; 94a3bb9fccSApple OSS Distributions } 95a3bb9fccSApple OSS Distributions 96a3bb9fccSApple OSS Distributions allocSize = round_page(size + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE); 97a3bb9fccSApple OSS Distributions 98a3bb9fccSApple OSS Distributions if (allocSize < size) { 99a3bb9fccSApple OSS Distributions return false; 100a3bb9fccSApple OSS Distributions } 101a3bb9fccSApple OSS Distributions 102a3bb9fccSApple OSS Distributions dataQueue = (IODataQueueMemory *)IOMallocAligned(allocSize, PAGE_SIZE); 103a5e72196SApple OSS Distributions if (dataQueue == NULL) { 104e13b1fa5SApple OSS Distributions return false; 105e13b1fa5SApple OSS Distributions } 1060f3703acSApple OSS Distributions bzero(dataQueue, allocSize); 107e13b1fa5SApple OSS Distributions 108e13b1fa5SApple OSS Distributions dataQueue->queueSize = size; 1090f3703acSApple OSS Distributions // dataQueue->head = 0; 1100f3703acSApple OSS Distributions // dataQueue->tail = 0; 111e13b1fa5SApple OSS Distributions 112a3bb9fccSApple OSS Distributions if (!setQueueSize(size)) { 113a3bb9fccSApple OSS Distributions return false; 114a3bb9fccSApple OSS Distributions } 115a3bb9fccSApple OSS Distributions 116e13b1fa5SApple OSS Distributions appendix = (IODataQueueAppendix *)((UInt8 *)dataQueue + size + DATA_QUEUE_MEMORY_HEADER_SIZE); 117e13b1fa5SApple OSS Distributions appendix->version = 0; 1180f3703acSApple OSS Distributions 1190f3703acSApple OSS Distributions if (!notifyMsg) { 1200f3703acSApple OSS Distributions notifyMsg = IOMalloc(sizeof(mach_msg_header_t)); 121a5e72196SApple OSS Distributions if (!notifyMsg) { 1220f3703acSApple OSS Distributions return false; 1230f3703acSApple OSS Distributions } 124a5e72196SApple OSS Distributions } 1250f3703acSApple OSS Distributions bzero(notifyMsg, sizeof(mach_msg_header_t)); 1260f3703acSApple OSS Distributions 127e13b1fa5SApple OSS Distributions setNotificationPort(MACH_PORT_NULL); 128e13b1fa5SApple OSS Distributions 129e13b1fa5SApple OSS Distributions return true; 130e13b1fa5SApple OSS Distributions } 131e13b1fa5SApple OSS Distributions 132a5e72196SApple OSS Distributions void 133a5e72196SApple OSS Distributions IOSharedDataQueue::free() 134e13b1fa5SApple OSS Distributions { 135e13b1fa5SApple OSS Distributions if (dataQueue) { 136a3bb9fccSApple OSS Distributions IOFreeAligned(dataQueue, round_page(getQueueSize() + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE)); 137e13b1fa5SApple OSS Distributions dataQueue = NULL; 1380f3703acSApple OSS Distributions if (notifyMsg) { 1390f3703acSApple OSS Distributions IOFree(notifyMsg, sizeof(mach_msg_header_t)); 1400f3703acSApple OSS Distributions notifyMsg = NULL; 1410f3703acSApple OSS Distributions } 142e13b1fa5SApple OSS Distributions } 143e13b1fa5SApple OSS Distributions 144a3bb9fccSApple OSS Distributions if (_reserved) { 145a3bb9fccSApple OSS Distributions IOFree(_reserved, sizeof(struct ExpansionData)); 146a3bb9fccSApple OSS Distributions _reserved = NULL; 147a3bb9fccSApple OSS Distributions } 148a3bb9fccSApple OSS Distributions 149e13b1fa5SApple OSS Distributions super::free(); 150e13b1fa5SApple OSS Distributions } 151e13b1fa5SApple OSS Distributions 152*bb611c8fSApple OSS Distributions OSSharedPtr<IOMemoryDescriptor> 153a5e72196SApple OSS Distributions IOSharedDataQueue::getMemoryDescriptor() 154e13b1fa5SApple OSS Distributions { 155*bb611c8fSApple OSS Distributions OSSharedPtr<IOMemoryDescriptor> descriptor; 156e13b1fa5SApple OSS Distributions 157a5e72196SApple OSS Distributions if (dataQueue != NULL) { 158a3bb9fccSApple OSS Distributions descriptor = IOMemoryDescriptor::withAddress(dataQueue, getQueueSize() + DATA_QUEUE_MEMORY_HEADER_SIZE + DATA_QUEUE_MEMORY_APPENDIX_SIZE, kIODirectionOutIn); 159e13b1fa5SApple OSS Distributions } 160e13b1fa5SApple OSS Distributions 161e13b1fa5SApple OSS Distributions return descriptor; 162e13b1fa5SApple OSS Distributions } 163e13b1fa5SApple OSS Distributions 164e13b1fa5SApple OSS Distributions 165a5e72196SApple OSS Distributions IODataQueueEntry * 166a5e72196SApple OSS Distributions IOSharedDataQueue::peek() 167e13b1fa5SApple OSS Distributions { 168a5e72196SApple OSS Distributions IODataQueueEntry *entry = NULL; 16988cc0b97SApple OSS Distributions UInt32 headOffset; 17088cc0b97SApple OSS Distributions UInt32 tailOffset; 171e13b1fa5SApple OSS Distributions 17288cc0b97SApple OSS Distributions if (!dataQueue) { 17388cc0b97SApple OSS Distributions return NULL; 17488cc0b97SApple OSS Distributions } 17588cc0b97SApple OSS Distributions 17688cc0b97SApple OSS Distributions // Read head and tail with acquire barrier 177cc9a6355SApple OSS Distributions // See rdar://problem/40780584 for an explanation of relaxed/acquire barriers 17888cc0b97SApple OSS Distributions headOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_RELAXED); 17988cc0b97SApple OSS Distributions tailOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_ACQUIRE); 18088cc0b97SApple OSS Distributions 18188cc0b97SApple OSS Distributions if (headOffset != tailOffset) { 182a5e72196SApple OSS Distributions volatile IODataQueueEntry * head = NULL; 183e13b1fa5SApple OSS Distributions UInt32 headSize = 0; 184e13b1fa5SApple OSS Distributions UInt32 headOffset = dataQueue->head; 185a3bb9fccSApple OSS Distributions UInt32 queueSize = getQueueSize(); 186a3bb9fccSApple OSS Distributions 187*bb611c8fSApple OSS Distributions if (headOffset > queueSize) { 188a3bb9fccSApple OSS Distributions return NULL; 189a3bb9fccSApple OSS Distributions } 190e13b1fa5SApple OSS Distributions 191e13b1fa5SApple OSS Distributions head = (IODataQueueEntry *)((char *)dataQueue->queue + headOffset); 192e13b1fa5SApple OSS Distributions headSize = head->size; 193e13b1fa5SApple OSS Distributions 194e13b1fa5SApple OSS Distributions // Check if there's enough room before the end of the queue for a header. 195e13b1fa5SApple OSS Distributions // If there is room, check if there's enough room to hold the header and 196e13b1fa5SApple OSS Distributions // the data. 197e13b1fa5SApple OSS Distributions 198a3bb9fccSApple OSS Distributions if ((headOffset > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) || 199a3bb9fccSApple OSS Distributions (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) || 200a3bb9fccSApple OSS Distributions (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headSize) || 201a3bb9fccSApple OSS Distributions (headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) { 202e13b1fa5SApple OSS Distributions // No room for the header or the data, wrap to the beginning of the queue. 203a3bb9fccSApple OSS Distributions // Note: wrapping even with the UINT32_MAX checks, as we have to support 204a3bb9fccSApple OSS Distributions // queueSize of UINT32_MAX 205e13b1fa5SApple OSS Distributions entry = dataQueue->queue; 206e13b1fa5SApple OSS Distributions } else { 207a5e72196SApple OSS Distributions entry = (IODataQueueEntry *)head; 208e13b1fa5SApple OSS Distributions } 209e13b1fa5SApple OSS Distributions } 210e13b1fa5SApple OSS Distributions 211e13b1fa5SApple OSS Distributions return entry; 212e13b1fa5SApple OSS Distributions } 213e13b1fa5SApple OSS Distributions 214a5e72196SApple OSS Distributions Boolean 215a5e72196SApple OSS Distributions IOSharedDataQueue::enqueue(void * data, UInt32 dataSize) 216a3bb9fccSApple OSS Distributions { 21788cc0b97SApple OSS Distributions UInt32 head; 21888cc0b97SApple OSS Distributions UInt32 tail; 21988cc0b97SApple OSS Distributions UInt32 newTail; 220a3bb9fccSApple OSS Distributions const UInt32 entrySize = dataSize + DATA_QUEUE_ENTRY_HEADER_SIZE; 221a3bb9fccSApple OSS Distributions IODataQueueEntry * entry; 222a3bb9fccSApple OSS Distributions 22388cc0b97SApple OSS Distributions // Force a single read of head and tail 224cc9a6355SApple OSS Distributions // See rdar://problem/40780584 for an explanation of relaxed/acquire barriers 22588cc0b97SApple OSS Distributions tail = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_RELAXED); 226cc9a6355SApple OSS Distributions head = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_ACQUIRE); 22788cc0b97SApple OSS Distributions 228a3bb9fccSApple OSS Distributions // Check for overflow of entrySize 229a3bb9fccSApple OSS Distributions if (dataSize > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) { 230a3bb9fccSApple OSS Distributions return false; 231a3bb9fccSApple OSS Distributions } 232a3bb9fccSApple OSS Distributions // Check for underflow of (getQueueSize() - tail) 2330f3703acSApple OSS Distributions if (getQueueSize() < tail || getQueueSize() < head) { 234a3bb9fccSApple OSS Distributions return false; 235a3bb9fccSApple OSS Distributions } 236a3bb9fccSApple OSS Distributions 237a5e72196SApple OSS Distributions if (tail >= head) { 238a3bb9fccSApple OSS Distributions // Is there enough room at the end for the entry? 239a3bb9fccSApple OSS Distributions if ((entrySize <= UINT32_MAX - tail) && 240a5e72196SApple OSS Distributions ((tail + entrySize) <= getQueueSize())) { 241a3bb9fccSApple OSS Distributions entry = (IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail); 242a3bb9fccSApple OSS Distributions 243a3bb9fccSApple OSS Distributions entry->size = dataSize; 244a5e72196SApple OSS Distributions __nochk_memcpy(&entry->data, data, dataSize); 245a3bb9fccSApple OSS Distributions 246a3bb9fccSApple OSS Distributions // The tail can be out of bound when the size of the new entry 247a3bb9fccSApple OSS Distributions // exactly matches the available space at the end of the queue. 248a3bb9fccSApple OSS Distributions // The tail can range from 0 to dataQueue->queueSize inclusive. 249a3bb9fccSApple OSS Distributions 25088cc0b97SApple OSS Distributions newTail = tail + entrySize; 251a5e72196SApple OSS Distributions } else if (head > entrySize) { // Is there enough room at the beginning? 252a3bb9fccSApple OSS Distributions // Wrap around to the beginning, but do not allow the tail to catch 253a3bb9fccSApple OSS Distributions // up to the head. 254a3bb9fccSApple OSS Distributions 255a3bb9fccSApple OSS Distributions dataQueue->queue->size = dataSize; 256a3bb9fccSApple OSS Distributions 257a3bb9fccSApple OSS Distributions // We need to make sure that there is enough room to set the size before 258a3bb9fccSApple OSS Distributions // doing this. The user client checks for this and will look for the size 259a3bb9fccSApple OSS Distributions // at the beginning if there isn't room for it at the end. 260a3bb9fccSApple OSS Distributions 261a5e72196SApple OSS Distributions if ((getQueueSize() - tail) >= DATA_QUEUE_ENTRY_HEADER_SIZE) { 262a3bb9fccSApple OSS Distributions ((IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail))->size = dataSize; 263a3bb9fccSApple OSS Distributions } 264a3bb9fccSApple OSS Distributions 265a5e72196SApple OSS Distributions __nochk_memcpy(&dataQueue->queue->data, data, dataSize); 26688cc0b97SApple OSS Distributions newTail = entrySize; 267a5e72196SApple OSS Distributions } else { 268a3bb9fccSApple OSS Distributions return false; // queue is full 269a3bb9fccSApple OSS Distributions } 270a5e72196SApple OSS Distributions } else { 271a3bb9fccSApple OSS Distributions // Do not allow the tail to catch up to the head when the queue is full. 272a3bb9fccSApple OSS Distributions // That's why the comparison uses a '>' rather than '>='. 273a3bb9fccSApple OSS Distributions 274a5e72196SApple OSS Distributions if ((head - tail) > entrySize) { 275a3bb9fccSApple OSS Distributions entry = (IODataQueueEntry *)((UInt8 *)dataQueue->queue + tail); 276a3bb9fccSApple OSS Distributions 277a3bb9fccSApple OSS Distributions entry->size = dataSize; 278a5e72196SApple OSS Distributions __nochk_memcpy(&entry->data, data, dataSize); 27988cc0b97SApple OSS Distributions newTail = tail + entrySize; 280a5e72196SApple OSS Distributions } else { 281a3bb9fccSApple OSS Distributions return false; // queue is full 282a3bb9fccSApple OSS Distributions } 283a3bb9fccSApple OSS Distributions } 284a3bb9fccSApple OSS Distributions 285cc9a6355SApple OSS Distributions // Publish the data we just enqueued 28688cc0b97SApple OSS Distributions __c11_atomic_store((_Atomic UInt32 *)&dataQueue->tail, newTail, __ATOMIC_RELEASE); 28788cc0b97SApple OSS Distributions 288cc9a6355SApple OSS Distributions if (tail != head) { 289cc9a6355SApple OSS Distributions // 290cc9a6355SApple OSS Distributions // The memory barrier below paris with the one in ::dequeue 291cc9a6355SApple OSS Distributions // so that either our store to the tail cannot be missed by 292cc9a6355SApple OSS Distributions // the next dequeue attempt, or we will observe the dequeuer 293cc9a6355SApple OSS Distributions // making the queue empty. 294cc9a6355SApple OSS Distributions // 295cc9a6355SApple OSS Distributions // Of course, if we already think the queue is empty, 296cc9a6355SApple OSS Distributions // there's no point paying this extra cost. 297cc9a6355SApple OSS Distributions // 298cc9a6355SApple OSS Distributions __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); 299cc9a6355SApple OSS Distributions head = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_RELAXED); 300a3bb9fccSApple OSS Distributions } 301a3bb9fccSApple OSS Distributions 302cc9a6355SApple OSS Distributions if (tail == head) { 303cc9a6355SApple OSS Distributions // Send notification (via mach message) that data is now available. 304cc9a6355SApple OSS Distributions sendDataAvailableNotification(); 305cc9a6355SApple OSS Distributions } 306a3bb9fccSApple OSS Distributions return true; 307a3bb9fccSApple OSS Distributions } 308a3bb9fccSApple OSS Distributions 309a5e72196SApple OSS Distributions Boolean 310a5e72196SApple OSS Distributions IOSharedDataQueue::dequeue(void *data, UInt32 *dataSize) 311e13b1fa5SApple OSS Distributions { 312e13b1fa5SApple OSS Distributions Boolean retVal = TRUE; 313a5e72196SApple OSS Distributions volatile IODataQueueEntry * entry = NULL; 314e13b1fa5SApple OSS Distributions UInt32 entrySize = 0; 31588cc0b97SApple OSS Distributions UInt32 headOffset = 0; 31688cc0b97SApple OSS Distributions UInt32 tailOffset = 0; 317e13b1fa5SApple OSS Distributions UInt32 newHeadOffset = 0; 318e13b1fa5SApple OSS Distributions 319cc9a6355SApple OSS Distributions if (!dataQueue || (data && !dataSize)) { 32088cc0b97SApple OSS Distributions return false; 32188cc0b97SApple OSS Distributions } 32288cc0b97SApple OSS Distributions 32388cc0b97SApple OSS Distributions // Read head and tail with acquire barrier 324cc9a6355SApple OSS Distributions // See rdar://problem/40780584 for an explanation of relaxed/acquire barriers 325cc9a6355SApple OSS Distributions headOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_RELAXED); 326cc9a6355SApple OSS Distributions tailOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_ACQUIRE); 32788cc0b97SApple OSS Distributions 32888cc0b97SApple OSS Distributions if (headOffset != tailOffset) { 329a5e72196SApple OSS Distributions volatile IODataQueueEntry * head = NULL; 330e13b1fa5SApple OSS Distributions UInt32 headSize = 0; 331a3bb9fccSApple OSS Distributions UInt32 queueSize = getQueueSize(); 332a3bb9fccSApple OSS Distributions 333a3bb9fccSApple OSS Distributions if (headOffset > queueSize) { 334a3bb9fccSApple OSS Distributions return false; 335a3bb9fccSApple OSS Distributions } 336e13b1fa5SApple OSS Distributions 337e13b1fa5SApple OSS Distributions head = (IODataQueueEntry *)((char *)dataQueue->queue + headOffset); 338e13b1fa5SApple OSS Distributions headSize = head->size; 339e13b1fa5SApple OSS Distributions 340a3bb9fccSApple OSS Distributions // we wrapped around to beginning, so read from there 341e13b1fa5SApple OSS Distributions // either there was not even room for the header 342a3bb9fccSApple OSS Distributions if ((headOffset > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) || 343a3bb9fccSApple OSS Distributions (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) || 344e13b1fa5SApple OSS Distributions // or there was room for the header, but not for the data 345a3bb9fccSApple OSS Distributions (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headSize) || 346a3bb9fccSApple OSS Distributions (headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) { 347a3bb9fccSApple OSS Distributions // Note: we have to wrap to the beginning even with the UINT32_MAX checks 348a3bb9fccSApple OSS Distributions // because we have to support a queueSize of UINT32_MAX. 349e13b1fa5SApple OSS Distributions entry = dataQueue->queue; 350e13b1fa5SApple OSS Distributions entrySize = entry->size; 351a3bb9fccSApple OSS Distributions if ((entrySize > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) || 352a3bb9fccSApple OSS Distributions (entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) { 353a3bb9fccSApple OSS Distributions return false; 354a3bb9fccSApple OSS Distributions } 355e13b1fa5SApple OSS Distributions newHeadOffset = entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE; 356e13b1fa5SApple OSS Distributions // else it is at the end 357e13b1fa5SApple OSS Distributions } else { 358e13b1fa5SApple OSS Distributions entry = head; 359e13b1fa5SApple OSS Distributions entrySize = entry->size; 360a3bb9fccSApple OSS Distributions if ((entrySize > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) || 361a3bb9fccSApple OSS Distributions (entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headOffset) || 362a3bb9fccSApple OSS Distributions (entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE + headOffset > queueSize)) { 363a3bb9fccSApple OSS Distributions return false; 364a3bb9fccSApple OSS Distributions } 365e13b1fa5SApple OSS Distributions newHeadOffset = headOffset + entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE; 366e13b1fa5SApple OSS Distributions } 367cc9a6355SApple OSS Distributions } else { 368cc9a6355SApple OSS Distributions // empty queue 369cc9a6355SApple OSS Distributions return false; 370e13b1fa5SApple OSS Distributions } 371e13b1fa5SApple OSS Distributions 372e13b1fa5SApple OSS Distributions if (data) { 373cc9a6355SApple OSS Distributions if (entrySize > *dataSize) { 374cc9a6355SApple OSS Distributions // not enough space 375cc9a6355SApple OSS Distributions return false; 376cc9a6355SApple OSS Distributions } 377a5e72196SApple OSS Distributions __nochk_memcpy(data, (void *)entry->data, entrySize); 378e13b1fa5SApple OSS Distributions *dataSize = entrySize; 379e13b1fa5SApple OSS Distributions } 380cc9a6355SApple OSS Distributions 381cc9a6355SApple OSS Distributions __c11_atomic_store((_Atomic UInt32 *)&dataQueue->head, newHeadOffset, __ATOMIC_RELEASE); 382cc9a6355SApple OSS Distributions 383cc9a6355SApple OSS Distributions if (newHeadOffset == tailOffset) { 384cc9a6355SApple OSS Distributions // 385cc9a6355SApple OSS Distributions // If we are making the queue empty, then we need to make sure 386cc9a6355SApple OSS Distributions // that either the enqueuer notices, or we notice the enqueue 387cc9a6355SApple OSS Distributions // that raced with our making of the queue empty. 388cc9a6355SApple OSS Distributions // 389cc9a6355SApple OSS Distributions __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); 390e13b1fa5SApple OSS Distributions } 391e13b1fa5SApple OSS Distributions 392e13b1fa5SApple OSS Distributions return retVal; 393e13b1fa5SApple OSS Distributions } 394e13b1fa5SApple OSS Distributions 395a5e72196SApple OSS Distributions UInt32 396a5e72196SApple OSS Distributions IOSharedDataQueue::getQueueSize() 397a3bb9fccSApple OSS Distributions { 398a3bb9fccSApple OSS Distributions if (!_reserved) { 399a3bb9fccSApple OSS Distributions return 0; 400a3bb9fccSApple OSS Distributions } 401a3bb9fccSApple OSS Distributions return _reserved->queueSize; 402a3bb9fccSApple OSS Distributions } 403a3bb9fccSApple OSS Distributions 404a5e72196SApple OSS Distributions Boolean 405a5e72196SApple OSS Distributions IOSharedDataQueue::setQueueSize(UInt32 size) 406a3bb9fccSApple OSS Distributions { 407a3bb9fccSApple OSS Distributions if (!_reserved) { 408a3bb9fccSApple OSS Distributions return false; 409a3bb9fccSApple OSS Distributions } 410a3bb9fccSApple OSS Distributions _reserved->queueSize = size; 411a3bb9fccSApple OSS Distributions return true; 412a3bb9fccSApple OSS Distributions } 413e13b1fa5SApple OSS Distributions 414e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 0); 415e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 1); 416e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 2); 417e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 3); 418e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 4); 419e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 5); 420e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 6); 421e13b1fa5SApple OSS Distributions OSMetaClassDefineReservedUnused(IOSharedDataQueue, 7); 422