QCDiskQueue::Status QCDiskQueue::Queue::GrowFile( QCDiskQueue::FileIdx inFileIdx, off_t inTargetSz) { QCStMutexLocker theLock(mMutex); if (! mRunFlag) { return Status(kErrorQueueStopped); } if (inFileIdx < 0 || inFileIdx >= mFileCount || mFdPtr[inFileIdx] < 0) { return Status(kErrorFileIdxOutOfRange); } const int64_t theOldSz = mFileInfoPtr[inFileIdx].mLastBlockIdx * mBlockSize; const int64_t theBlkIdx = (int64_t(inTargetSz > 0 ? inTargetSz : theOldSz) + mBlockSize - 1) / mBlockSize; if (theBlkIdx >= (int64_t(1) << kBlockBitCount)) { return Status(kErrorSpaceAlloc); } mFileInfoPtr[inFileIdx].mSpaceAllocPendingFlag = inTargetSz > 0 && inTargetSz > theOldSz; mFileInfoPtr[inFileIdx].mLastBlockIdx = theBlkIdx; mFileInfoPtr[inFileIdx].mSpaceAllocPendingFlag = true; return Status(kErrorNone); }
bool ZCnd_boost::Wait(boost::mutex& iMtx, double iTimeout) { boost::mutex::scoped_lock theLock(iMtx, boost::adopt_lock); return condition_variable::timed_wait( theLock, boost::posix_time::microseconds(iTimeout * 1e6)); }
void Remove( QCThread& inThread) { QCStMutexLocker theLock(mMutex); ThreadList::Remove(inThread); mCount--; }
//********************************************************************************************** // WCMRAudioDeviceManager::~WCMRAudioDeviceManager // //! It clears the device list, releasing each of the device. //! //! \param none //! //! \return Nothing. //! //********************************************************************************************** WCMRAudioDeviceManager::~WCMRAudioDeviceManager() { AUTO_FUNC_DEBUG; std::cout << "API::Destroying AudioDeviceManager " << std::endl; try { // clean up device info list { wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); while( m_DeviceInfoVec.size() ) { DeviceInfo* devInfo = m_DeviceInfoVec.back(); m_DeviceInfoVec.pop_back(); delete devInfo; } } delete m_CurrentDevice; } catch (...) { //destructors should absorb exceptions, no harm in logging though!! DEBUG_MSG ("Exception during destructor"); } }
QCDiskQueue::CloseFileStatus QCDiskQueue::Queue::CloseFile( QCDiskQueue::FileIdx inFileIdx, int64_t inFileSize) { QCStMutexLocker theLock(mMutex); if (inFileIdx < 0 || inFileIdx >= mFileCount || mFdPtr[inFileIdx] < 0) { return CloseFileStatus(kErrorParameter, 0); } if (mFilePendingReqCountPtr[inFileIdx] > 0) { return CloseFileStatus(kErrorHasPendingRequests, 0); } int theSysErr = 0; const int theFd = mFdPtr[inFileIdx]; for (int i = inFileIdx + mFileCount; i < mFdCount; i += mFileCount) { if (close(mFdPtr[i])) { theSysErr = errno ? errno : -1; } mFdPtr[i] = -1; } mFdPtr[inFileIdx] = mFreeFdHead; mFreeFdHead = -(inFileIdx + kFreeFdOffset); theLock.Unlock(); if (theFd >= 0) { if (inFileSize >= 0 && inFileSize < mBlockSize * int64_t(mFileInfoPtr[inFileIdx].mLastBlockIdx) && ftruncate(theFd, (off_t)inFileSize)) { theSysErr = errno ? errno : -1; } if (close(theFd)) { theSysErr = errno ? errno : -1; } } return CloseFileStatus(theSysErr ? kErrorClose : kErrorNone, theSysErr); }
void Insert( QCThread& inThread) { QCStMutexLocker theLock(mMutex); ThreadList::Insert(inThread, ThreadList::GetPrev(mHead)); mCount++; }
CompletionStatus Wait() { QCStMutexLocker theLock(mMutex); while (! mDoneFlag) { mDoneCond.Wait(mMutex); } return mCompletionStatus; }
QCDiskQueue::OpenFileStatus QCDiskQueue::Queue::OpenFile( const char* inFileNamePtr, int64_t inMaxFileSize, bool inReadOnlyFlag, bool inAllocateFileSpaceFlag, bool inCreateFlag) { QCStMutexLocker theLock(mMutex); if (mFreeFdHead == kFreeFdEnd) { return OpenFileStatus(-1, kErrorFileIdxOutOfRange, 0); } const int theIdx = -mFreeFdHead - kFreeFdOffset; QCRTASSERT( theIdx >= 0 && theIdx < mFileCount && mFdPtr[theIdx] <= kFreeFdEnd); mFreeFdHead = mFdPtr[theIdx]; int theSysErr = 0; for (int i = theIdx; i < mFdCount; i += mFileCount) { const int theFd = open(inFileNamePtr, kOpenCommonFlags | (inCreateFlag ? O_CREAT : 0) | (inReadOnlyFlag ? O_RDONLY : O_RDWR), S_IRUSR | S_IWUSR); if (theFd < 0 || fcntl(theFd, FD_CLOEXEC, 1)) { theSysErr = errno ? errno : -1; break; } mFdPtr[i] = theFd; if (i >= mFileCount) { continue; } const off_t theSize = lseek(theFd, 0, SEEK_END); if (theSize < 0) { theSysErr = errno; break; } mFilePendingReqCountPtr[i] = 0; const int64_t theBlkIdx = (int64_t(inMaxFileSize < 0 ? theSize : inMaxFileSize) + mBlockSize - 1) / mBlockSize; if (theBlkIdx >= (int64_t(1) << kBlockBitCount)) { theSysErr = EOVERFLOW; break; } mFileInfoPtr[i].mLastBlockIdx = theBlkIdx; mFileInfoPtr[i].mSpaceAllocPendingFlag = inAllocateFileSpaceFlag && ! inReadOnlyFlag && inMaxFileSize > 0 && theSize < inMaxFileSize; } if (! theSysErr) { return OpenFileStatus(theIdx, kErrorNone, theSysErr); } for (int i = theIdx; i < mFdCount; i += mFileCount) { close(mFdPtr[i]); mFdPtr[i] = -1; } mFdPtr[theIdx] = mFreeFdHead; mFreeFdHead = -(theIdx + kFreeFdOffset); return OpenFileStatus(-1, kErrorOpen, theSysErr); }
/*static*/ void VCacheLog::Destroy() { if(s_cacheLog != NULL) { VTaskLock theLock(&s_mutex); delete s_cacheLog; s_cacheLog = NULL; } }
void GetPendingCount( int& outFreeRequestCount, int& outRequestCount, int64_t& outReadBlockCount, int64_t& outWriteBlockCount) { QCStMutexLocker theLock(mMutex); outFreeRequestCount = mFreeCount; outRequestCount = mPendingCount; outReadBlockCount = mPendingReadBlockCount; outWriteBlockCount = mPendingWriteBlockCount; }
/*static*/ VCacheLog * VCacheLog::Get() { if(s_cacheLog == NULL) { VTaskLock theLock(&s_mutex); if(s_cacheLog == NULL) { s_cacheLog = new VCacheLog; } } return s_cacheLog; }
bool QCDiskQueue::Queue::Cancel( QCDiskQueue::RequestId inRequestId) { QCStMutexLocker theLock(mMutex); return ( mPendingCount > 0 && inRequestId >= kRequestQueueCount && inRequestId < mTotalCount && ! mRequestsPtr[inRequestId].mInFlightFlag && Cancel(mRequestsPtr[inRequestId]) ); }
QCDiskQueue::Status QCDiskQueue::Queue::UnReserveFileSpace(QCDiskQueue::FileIdx inFileIdx, off_t inStartOffset, off_t inLen) { QCStMutexLocker theLock(mMutex); if (! mRunFlag) { return Status(kErrorQueueStopped); } if (inFileIdx < 0 || inFileIdx >= mFileCount || mFdPtr[inFileIdx] < 0) { return Status(kErrorFileIdxOutOfRange); } QCUtils::UnReserveFileSpace(mFdPtr[inFileIdx], inStartOffset, inLen); return Status(kErrorNone); }
QCDiskQueue::Status QCDiskQueue::Queue::AllocateFileSpace( QCDiskQueue::FileIdx inFileIdx) { QCStMutexLocker theLock(mMutex); if (! mRunFlag) { return Status(kErrorQueueStopped); } if (inFileIdx < 0 || inFileIdx >= mFileCount || mFdPtr[inFileIdx] < 0) { return Status(kErrorFileIdxOutOfRange); } mFileInfoPtr[inFileIdx].mSpaceAllocPendingFlag = true; return Status(kErrorNone); }
WTErr WCMRAudioDeviceManager::GetDeviceInfoByName(const std::string & nameToMatch, DeviceInfo & devInfo) const { wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); DeviceInfoVecConstIter iter = m_DeviceInfoVec.begin(); for (; iter != m_DeviceInfoVec.end(); ++iter) { if (nameToMatch == (*iter)->m_DeviceName) { devInfo = *(*iter); return eNoErr; } } return eRMResNotFound; }
virtual bool Done( RequestId inRequestId, FileIdx inFileIdx, BlockIdx inStartBlockIdx, InputIterator& inBufferItr, int inBufferCount, Error inCompletionCode, int inSysErrorCode, int64_t inIoByteCount) { QCStMutexLocker theLock(mMutex); mDoneFlag = true; mCompletionStatus = CompletionStatus(inCompletionCode, inSysErrorCode, inIoByteCount); CopyBufs(&inBufferItr, inBufferCount); mDoneCond.Notify(); return true; }
QCDiskQueue::EnqueueStatus QCDiskQueue::Queue::Sync( QCDiskQueue::FileIdx inFileIdx, QCDiskQueue::IoCompletion* inIoCompletionPtr, QCDiskQueue::Time inTimeWaitNanoSec) { QCStMutexLocker theLock(mMutex); if (! mRunFlag) { return EnqueueStatus(kRequestIdNone, kErrorQueueStopped); } if (inFileIdx < 0 || inFileIdx >= mFileCount || mFdPtr[inFileIdx] < 0) { return EnqueueStatus(kRequestIdNone, kErrorFileIdxOutOfRange); } Request* theReqPtr; if (! (theReqPtr = Get(0))) { QCStValueIncrementor<int> theIncr(mReqWaitersCount, 1); if (inTimeWaitNanoSec < 0) { mFreeReqCond.Wait(mMutex); } else if (inTimeWaitNanoSec == 0 || ! mFreeReqCond.Wait(mMutex, inTimeWaitNanoSec)) { if (inTimeWaitNanoSec != 0) { theLock.Detach(); } return EnqueueStatus(kRequestIdNone, kErrorOutOfRequests); } } QCASSERT(theReqPtr); // FIXME: implement real io barrier, for now just queue empty read request. Request& theReq = *theReqPtr; theReq.mReqType = kReqTypeRead; theReq.mBufferCount = 0; theReq.mFileIdx = inFileIdx; theReq.mBlockIdx = 0; theReq.mIoCompletionPtr = inIoCompletionPtr; char** const theBufsPtr = GetBuffersPtr(theReq); theBufsPtr[0] = 0; return EnqueueStatus(kErrorNone); }
/* virtual */ void QCDiskQueue::Queue::Run( int inThreadIndex) { QCStMutexLocker theLock(mMutex); QCASSERT(inThreadIndex >= 0 && inThreadIndex < mThreadCount); int* const theFdPtr = mFdPtr + mFdCount / mThreadCount * inThreadIndex; struct iovec* const theIoVecPtr = mIoVecPtr + mIoVecPerThreadCount * inThreadIndex; while (mRunFlag) { Request* theReqPtr; while (! (theReqPtr = Dequeue()) && mRunFlag) { mWorkCond.Wait(mMutex); } if (mRunFlag) { QCASSERT(theReqPtr); Process(*theReqPtr, theFdPtr, theIoVecPtr); } else if (theReqPtr) { Cancel(*theReqPtr); } } }
QCDiskQueue::IoCompletion* QCDiskQueue::Queue::CancelOrSetCompletionIfInFlight( QCDiskQueue::RequestId inRequestId, QCDiskQueue::IoCompletion* inCompletionIfInFlightPtr) { QCStMutexLocker theLock(mMutex); if (mPendingCount <= 0 || inRequestId < kRequestQueueCount || inRequestId >= mTotalCount) { return 0; } Request& theReq = mRequestsPtr[inRequestId]; if (theReq.mReqType == kReqTypeNone) { // Completion is already running, or done. return theReq.mIoCompletionPtr; } if (! theReq.mInFlightFlag) { IoCompletion* const theIoCompletionPtr = theReq.mIoCompletionPtr; return (Cancel(theReq) ? theIoCompletionPtr : 0); } // In flight, change io completion. theReq.mIoCompletionPtr = inCompletionIfInFlightPtr; return inCompletionIfInFlightPtr; }
void Stop() { QCStMutexLocker theLock(mMutex); StopSelf(); }
const DeviceInfoVec WCMRAudioDeviceManager::DeviceInfoList() const { wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); return m_DeviceInfoVec; }
int GetThreadCount() { QCStMutexLocker theLock(mMutex); return mCount; }
void ZCnd_boost::Wait(boost::mutex& iMtx) { boost::mutex::scoped_lock theLock(iMtx, boost::adopt_lock); condition_variable::wait(theLock); }
void QCDiskQueue::Queue::Process( Request& inReq, int* inFdPtr, struct iovec* inIoVecPtr) { QCASSERT(mMutex.IsOwned()); QCASSERT(mIoVecPerThreadCount > 0 && mBufferPoolPtr); QCRTASSERT(//mFileInfoPtr[inReq.mFileIdx].mLastBlockIdx >= 0 && inReq.mBlockIdx + inReq.mBufferCount <= uint64_t(mFileInfoPtr[inReq.mFileIdx].mLastBlockIdx)); const int theFd = inFdPtr[inReq.mFileIdx]; char** const theBufPtr = GetBuffersPtr(inReq); const off_t theOffset = (off_t)inReq.mBlockIdx * mBlockSize; const bool theReadFlag = inReq.mReqType == kReqTypeRead; const int64_t theAllocSize = (inReq.mReqType == kReqTypeWrite && mFileInfoPtr[inReq.mFileIdx].mSpaceAllocPendingFlag) ? mFileInfoPtr[inReq.mFileIdx].mLastBlockIdx * mBlockSize : 0; QCASSERT((theReadFlag || inReq.mReqType == kReqTypeWrite) && theFd >= 0); inReq.mInFlightFlag = true; QCStMutexUnlocker theUnlock(mMutex); Error theError = kErrorNone; int theSysError = 0; if (theAllocSize > 0) { // Theoretically space allocation can be simultaneously invoked from // more than one io thread. This is to ensure that allocation always // happen before the first write. // OS can deal with concurrent allocations. const int64_t theResv = QCUtils::ReserveFileSpace(theFd, theAllocSize); if (theResv < 0) { theError = kErrorSpaceAlloc; theSysError = int(-theResv); } if (theResv > 0 && ftruncate(theFd, theAllocSize)) { theError = kErrorSpaceAlloc; theSysError = errno; } if (theError == kErrorNone) { QCStMutexLocker theLock(mMutex); mFileInfoPtr[inReq.mFileIdx].mSpaceAllocPendingFlag = false; } } const bool theGetBufFlag = ! theBufPtr[0]; if (theError == kErrorNone && theGetBufFlag) { QCASSERT(theReadFlag); BuffersIterator theIt(*this, inReq, inReq.mBufferCount); // Allocate buffers for read request. if (! mBufferPoolPtr->Get(theIt, inReq.mBufferCount, QCIoBufferPool::kRefillReqIdRead)) { theError = kErrorOutOfBuffers; } } if (theError == kErrorNone && lseek(theFd, theOffset, SEEK_SET) != theOffset) { theError = kErrorSeek; theSysError = errno; } BuffersIterator theItr(*this, inReq, inReq.mBufferCount); int theBufCnt = inReq.mBufferCount; int64_t theIoByteCnt = 0; while (theBufCnt > 0 && theError == kErrorNone) { ssize_t theIoBytes = 0; int theIoVecCnt = 0; char* thePtr; while (theIoVecCnt < mIoVecPerThreadCount && (thePtr = theItr.Get())) { inIoVecPtr[theIoVecCnt ].iov_base = thePtr; inIoVecPtr[theIoVecCnt++].iov_len = mBlockSize; theIoBytes += mBlockSize; theBufCnt--; } QCRTASSERT(theIoVecCnt > 0); if (theReadFlag) { const ssize_t theNRd = readv(theFd, inIoVecPtr, theIoVecCnt); if (theNRd < 0) { theError = kErrorRead; theSysError = theNRd < 0 ? errno : 0; break; } theIoByteCnt += theNRd; if (theNRd < theIoBytes) { if (theGetBufFlag) { // Short read -- release extra buffers. mBufferPoolPtr->Put(theItr, theBufCnt); inReq.mBufferCount -= theBufCnt; int i = (theNRd + mBlockSize - 1) / mBlockSize; inReq.mBufferCount -= theIoVecCnt - i; while (i < theIoVecCnt) { mBufferPoolPtr->Put((char*)inIoVecPtr[i++].iov_base); } } break; } } else { const ssize_t theNWr = writev(theFd, inIoVecPtr, theIoVecCnt); if (theNWr > 0) { theIoByteCnt += theNWr; } if (theNWr != theIoBytes) { theError = kErrorWrite; theSysError = errno; break; } } } if (theGetBufFlag && theError != kErrorNone && theBufPtr[0]) { BuffersIterator theIt(*this, inReq, inReq.mBufferCount); mBufferPoolPtr->Put(theIt, inReq.mBufferCount); theBufPtr[0] = 0; } theUnlock.Lock(); RequestComplete(inReq, theError, theSysError, theIoByteCnt, theGetBufFlag); }
int QCDiskQueue::Queue::Start( int inThreadCount, int inMaxQueueDepth, int inMaxBuffersPerRequestCount, int inFileCount, const char** inFileNamesPtr, QCIoBufferPool& inBufferPool) { QCStMutexLocker theLock(mMutex); StopSelf(); if (inFileCount <= 0 || inThreadCount <= 0 || inThreadCount <= 0 || inMaxQueueDepth <= 0 || inMaxBuffersPerRequestCount <= 0) { return 0; } if (inFileCount >= (1 << kFileIndexBitCount)) { return EINVAL; } mBufferPoolPtr = &inBufferPool; #ifdef IOV_MAX const int kMaxIoVecCount = IOV_MAX; #else const int kMaxIoVecCount = 1 << 10; #endif mIoVecPerThreadCount = inMaxBuffersPerRequestCount; if (mIoVecPerThreadCount > kMaxIoVecCount) { mIoVecPerThreadCount = kMaxIoVecCount; } mFileCount = inFileCount; mIoVecPtr = new struct iovec[mIoVecPerThreadCount * inThreadCount]; mBlockSize = inBufferPool.GetBufferSize(); const int theFdCount = inThreadCount * mFileCount; mFdPtr = new int[theFdCount]; mFilePendingReqCountPtr = new unsigned int[mFileCount]; mFileInfoPtr = new FileInfo[mFileCount]; mFreeFdHead = kFreeFdEnd; for (mFdCount = 0; mFdCount < theFdCount; ) { int theError = 0; for (int i = 0; i < mFileCount; i++) { int& theFd = mFdPtr[mFdCount]; theFd = inFileNamesPtr ? open(inFileNamesPtr[i], kOpenCommonFlags | O_RDWR) : -1; if (theFd < 0 && inFileNamesPtr) { theError = errno; break; } if (theFd >= 0 && fcntl(theFd, FD_CLOEXEC, 1)) { theError = errno; break; } if (++mFdCount > mFileCount) { continue; } const off_t theSize = theFd >= 0 ? lseek(theFd, 0, SEEK_END) : 0; if (theSize < 0) { theError = errno; break; } mFilePendingReqCountPtr[i] = 0; // Allow last partial block. const int64_t theBlkIdx = (int64_t(theSize) + mBlockSize - 1) / mBlockSize; if (theBlkIdx >= (int64_t(1) << kBlockBitCount)) { theError = EOVERFLOW; break; } mFileInfoPtr[i].mLastBlockIdx = theBlkIdx; mFileInfoPtr[i].mSpaceAllocPendingFlag = false; if (theFd < 0) { theFd = mFreeFdHead; mFreeFdHead = -(i + kFreeFdOffset); } } if (theError) { StopSelf(); return theError; } } mBuffersPtr = new char*[inMaxQueueDepth * inMaxBuffersPerRequestCount]; mRequestBufferCount = inMaxBuffersPerRequestCount; const int theReqCnt = kRequestQueueCount + inMaxQueueDepth; mRequestsPtr = new Request[theReqCnt]; // Init list heads: kFreeQueueIdx kIoQueueIdx. for (mTotalCount = 0; mTotalCount < kRequestQueueCount; mTotalCount++) { Init(mRequestsPtr[mTotalCount]); } // Make free list. for (; mTotalCount < theReqCnt; mTotalCount++) { Request& theReq = mRequestsPtr[mTotalCount]; Init(theReq); Put(theReq); } mThreadsPtr = new IoThread[inThreadCount]; mRunFlag = true; const int kStackSize = 32 << 10; const char* const kNamePtr = "IO"; for (mThreadCount = 0; mThreadCount < inThreadCount; mThreadCount++) { const int theRet = mThreadsPtr[mThreadCount].Start( *this, mThreadCount, kStackSize, kNamePtr); if (theRet != 0) { StopSelf(); return theRet; } } return 0; }
QCDiskQueue::EnqueueStatus QCDiskQueue::Queue::Enqueue( QCDiskQueue::ReqType inReqType, QCDiskQueue::FileIdx inFileIdx, QCDiskQueue::BlockIdx inBlockIdx, QCDiskQueue::InputIterator* inBufferIteratorPtr, int inBufferCount, QCDiskQueue::IoCompletion* inIoCompletionPtr, QCDiskQueue::Time inTimeWaitNanoSec) { if ((inReqType != kReqTypeRead && inReqType != kReqTypeWrite) || inBufferCount <= 0 || inBufferCount > (mRequestBufferCount * (mTotalCount - kRequestQueueCount)) || (! inBufferIteratorPtr && inReqType == kReqTypeWrite)) { return EnqueueStatus(kRequestIdNone, kErrorParameter); } QCStMutexLocker theLock(mMutex); if (! mRunFlag) { return EnqueueStatus(kRequestIdNone, kErrorQueueStopped); } if (inFileIdx < 0 || inFileIdx >= mFileCount || mFdPtr[inFileIdx] < 0) { return EnqueueStatus(kRequestIdNone, kErrorFileIdxOutOfRange); } if (inBlockIdx < 0 || inBlockIdx + (inBufferIteratorPtr ? 0 : inBufferCount) > int64_t(mFileInfoPtr[inFileIdx].mLastBlockIdx)) { return EnqueueStatus(kRequestIdNone, kErrorBlockIdxOutOfRange); } Request* theReqPtr; while (! (theReqPtr = Get(inBufferCount))) { QCStValueIncrementor<int> theIncr(mReqWaitersCount, 1); if (inTimeWaitNanoSec < 0) { mFreeReqCond.Wait(mMutex); } else if (inTimeWaitNanoSec == 0 || ! mFreeReqCond.Wait(mMutex, inTimeWaitNanoSec)) { if (inTimeWaitNanoSec != 0) { theLock.Detach(); } return EnqueueStatus(kRequestIdNone, kErrorOutOfRequests); } } QCASSERT(theReqPtr); Request& theReq = *theReqPtr; theReq.mReqType = inReqType; theReq.mBufferCount = 0; theReq.mFileIdx = inFileIdx; theReq.mBlockIdx = inBlockIdx; theReq.mIoCompletionPtr = inIoCompletionPtr; if (inBufferIteratorPtr) { BuffersIterator theItr(*this, theReq, inBufferCount); for (int i = 0; i < inBufferCount; i++) { char* const thePtr = inBufferIteratorPtr->Get(); if (! thePtr) { break; } theItr.Put(thePtr); theReq.mBufferCount++; } if (theReq.mBufferCount < inBufferCount) { // Free unused requests if any. TrimRequestList(theReq, theReq.mBufferCount); } } else if (inReqType == kReqTypeRead) { // Defer buffer allocation. GetBuffersPtr(theReq)[0] = 0; theReq.mBufferCount = inBufferCount; } if (theReq.mBlockIdx + theReq.mBufferCount > uint64_t(mFileInfoPtr[theReq.mFileIdx].mLastBlockIdx)) { Put(theReq); return EnqueueStatus(kRequestIdNone, kErrorBlockIdxOutOfRange); } if (theReq.mBufferCount <= 0) { Put(theReq); return EnqueueStatus(kRequestIdNone, kErrorBlockCountOutOfRange); } Enqueue(theReq); mWorkCond.Notify(); return GetRequestId(theReq); }