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