bool OutboundSSLProtocol::DoHandshake() { if (_sslHandshakeCompleted) return true; int32_t errorCode = SSL_ERROR_NONE; errorCode = SSL_connect(_pSSL); if (errorCode < 0) { int32_t error = SSL_get_error(_pSSL, errorCode); if (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE) { FATAL("Unable to connect SSL: %d; %s", error, STR(GetSSLErrors())); return false; } } _sslHandshakeCompleted = SSL_is_init_finished(_pSSL); if (!PerformIO()) { FATAL("Unable to perform I/O"); return false; } if (_sslHandshakeCompleted) return EnqueueForOutbound(); return true; }
bool BaseSSLProtocol::SignalInputData(IOBuffer &buffer) { //1. get the SSL input buffer BIO *pInBio = SSL_get_rbio(_pSSL); //2. dump all the data from the network inside the ssl input BIO_write(pInBio, GETIBPOINTER(buffer), GETAVAILABLEBYTESCOUNT(buffer)); buffer.IgnoreAll(); //3. Do we have to do some handshake? if (!_sslHandshakeCompleted) { if (!DoHandshake()) { FATAL("Unable to do the SSL handshake"); return false; } if (!_sslHandshakeCompleted) { return true; } } //4. Read the actual data an put it in the descrypted input buffer int32_t read = 0; while ((read = SSL_read(_pSSL, _pReadBuffer, MAX_SSL_READ_BUFFER)) > 0) { _inputBuffer.ReadFromBuffer(_pReadBuffer, (uint32_t) read); } if (read < 0) { int32_t error = SSL_get_error(_pSSL, read); if (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE) { FATAL("Unable to read data: %d", error); return false; } } //6. If we have pending data inside the decrypted buffer, bubble it up on the protocol stack if (GETAVAILABLEBYTESCOUNT(_inputBuffer) > 0) { if (_pNearProtocol != NULL) { if (!_pNearProtocol->SignalInputData(_inputBuffer)) { FATAL("Unable to signal near protocol for new data"); return false; } } } //7. After the data was sent on the upper layers, we might have outstanding //data that needs to be sent. return PerformIO(); }
bool BaseSSLProtocol::EnqueueForOutbound() { //1. Is the SSL handshake completed? if (!_sslHandshakeCompleted) { return DoHandshake(); } //2. Do we have some outstanding data? IOBuffer *pBuffer = _pNearProtocol->GetOutputBuffer(); if (pBuffer == NULL) return true; //3. Encrypt the outstanding data if (SSL_write(_pSSL, GETIBPOINTER(*pBuffer), GETAVAILABLEBYTESCOUNT(*pBuffer)) != (int32_t) GETAVAILABLEBYTESCOUNT(*pBuffer)) { FATAL("Unable to write %u bytes", GETAVAILABLEBYTESCOUNT(*pBuffer)); return false; } pBuffer->IgnoreAll(); //4. Do the actual I/O return PerformIO(); }
void DevBeginIO( struct AHIRequest* ioreq, struct AHIBase* AHIBase ) { if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW) { KPrintF("BeginIO(0x%08lx)\n", ioreq); } ioreq->ahir_Std.io_Message.mn_Node.ln_Type = NT_MESSAGE; switch(ioreq->ahir_Std.io_Command) { // Immediate commands case NSCMD_DEVICEQUERY: case CMD_STOP: case CMD_FLUSH: PerformIO(ioreq,AHIBase); break; // Queued commands case CMD_RESET: case CMD_READ: case CMD_WRITE: case CMD_START: ioreq->ahir_Std.io_Flags &= ~IOF_QUICK; PutMsg(&ioreq->ahir_Std.io_Unit->unit_MsgPort,&ioreq->ahir_Std.io_Message); break; // Unknown commands default: ioreq->ahir_Std.io_Error = IOERR_NOCMD; TermIO(ioreq,AHIBase); break; } }
DWORD InstallSoftwareDeviceInterface(IN LPGUID DeviceId, IN LPGUID InterfaceId, IN LPWSTR ReferenceString) { HDEVINFO hDevInfo; SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; GUID SWBusGuid = {STATIC_BUSID_SoftwareDeviceEnumerator}; PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData; HANDLE hDevice; PSWENUM_INSTALL_INTERFACE InstallInterface; DWORD dwResult; hDevInfo = SetupDiGetClassDevsW(&SWBusGuid, NULL, NULL, DIGCF_DEVICEINTERFACE| DIGCF_PRESENT); if (!hDevInfo) { // failed return GetLastError(); } DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); if (!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &SWBusGuid, 0, &DeviceInterfaceData)) { // failed SetupDiDestroyDeviceInfoList(hDevInfo); return GetLastError(); } DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W)); if (!DeviceInterfaceDetailData) { // failed SetupDiDestroyDeviceInfoList(hDevInfo); return GetLastError(); } DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); if (!SetupDiGetDeviceInterfaceDetailW(hDevInfo, &DeviceInterfaceData, DeviceInterfaceDetailData,MAX_PATH * sizeof(WCHAR) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W), NULL, NULL)) { // failed HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData); SetupDiDestroyDeviceInfoList(hDevInfo); return GetLastError(); } hDevice = CreateFileW(DeviceInterfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_NORMAL, NULL); if (hDevice == INVALID_HANDLE_VALUE) { // failed HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData); SetupDiDestroyDeviceInfoList(hDevInfo); return GetLastError(); } InstallInterface = (PSWENUM_INSTALL_INTERFACE)HeapAlloc(GetProcessHeap(), 0, sizeof(SWENUM_INSTALL_INTERFACE) + wcslen(ReferenceString) * sizeof(WCHAR)); if (!InstallInterface) { // failed CloseHandle(hDevice); HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData); SetupDiDestroyDeviceInfoList(hDevInfo); return GetLastError(); } // init install interface param InstallInterface->DeviceId = *DeviceId; InstallInterface->InterfaceId = *InterfaceId; wcscpy(InstallInterface->ReferenceString, ReferenceString); PerformIO(hDevice, IOCTL_SWENUM_INSTALL_INTERFACE, InstallInterface, sizeof(SWENUM_INSTALL_INTERFACE) + wcslen(ReferenceString) * sizeof(WCHAR), NULL, 0, NULL); dwResult = HeapFree(GetProcessHeap(), 0, InstallInterface); CloseHandle(hDevice); HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData); SetupDiDestroyDeviceInfoList(hDevInfo); return dwResult; }
void CheapieBlade::On() { mLedPowerLevel = 255; PerformIO(); }
void CheapieBlade::Off() { mLedPowerLevel = 0; PerformIO(); }
void ZKMORHP_IOThreadSlave::WorkLoop() { // grab the IO guard bool wasLocked = mIOGuard.Lock(); // initialize some stuff mWorkLoopPhase = kInitializingPhase; mIOCycleCounter = 0; mOverloadCounter = 0; CAPropertyAddress theIsRunningAddress(kAudioDevicePropertyDeviceIsRunning); mDevice->GetIOCycleTelemetry().IOCycleInitializeBegin(mIOCycleCounter); try { // and signal that the IO thread is running mIOGuard.NotifyAll(); // initialize the work loop stopping conditions mStopWorkLoop = false; // Tell the device that the IO thread has initialized. Note that we unlock around this call // due to the fact that IOCycleInitialize might not return for a while because it might // have to wait for the hardware to start. if(wasLocked) { mIOGuard.Unlock(); } // tell the device that the IO cycle is initializing to start the timing services mDevice->StartIOCycleTimingServices(); // set the device state to know the engine is running mDevice->IOEngineStarted(); // notify clients that the engine is running mDevice->PropertiesChanged(1, &theIsRunningAddress); // re-lock the guard wasLocked = mIOGuard.Lock(); // make sure the thread is still running before moving on if(!mStopWorkLoop) { // set the time constraints for the IOThread SetTimeConstraints(); // initialize the clock mDevice->EstablishIOCycleAnchorTime(mAnchorTime); mFrameCounter = 0; #if Offset_For_Input if(mDevice->HasInputStreams()) { // the first sleep cycle as to be at least the input safety offset and a buffer's // worth of time to be sure that the input data is all there mFrameCounter += mDevice->GetSafetyOffset(true); } #endif // enter the work loop mWorkLoopPhase = kRunningPhase; bool isInNeedOfResynch = false; mDevice->GetIOCycleTelemetry().IOCycleInitializeEnd(mIOCycleCounter, mAnchorTime); while(!mStopWorkLoop) { // get the current time AudioTimeStamp theCurrentTime; mDevice->GetCurrentTime(theCurrentTime); // calculate the next wake up time AudioTimeStamp theNextWakeUpTime = CAAudioTimeStamp::kZero; theNextWakeUpTime.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid; if(CalculateNextWakeUpTime(theCurrentTime, theNextWakeUpTime, isInNeedOfResynch, wasLocked)) { // sleep until the next wake up time mDevice->GetIOCycleTelemetry().IOCycleWorkLoopEnd(mIOCycleCounter, theCurrentTime, theNextWakeUpTime); mIOGuard.WaitUntil(CAHostTimeBase::ConvertToNanos(theNextWakeUpTime.mHostTime)); // increment the counter ++mIOCycleCounter; // do IO if the thread wasn't stopped if(!mStopWorkLoop) { // get the current time mDevice->GetCurrentTime(theCurrentTime); #if Log_SchedulingLatency // check to see if we have incurred a large scheduling latency if(theCurrentTime.mHostTime > (theNextWakeUpTime.mHostTime + mAllowedLatency)) { // log it mLatencyLog->Capture(theNextWakeUpTime.mHostTime - mAllowedLatency, theCurrentTime.mHostTime, true); // print how late we are DebugMessageN1("HP_IOThread::WorkLoop: woke up late by %f milliseconds", ((Float64)CAHostTimeBase::ConvertToNanos(theCurrentTime.mHostTime - theNextWakeUpTime.mHostTime)) / (1000.0 * 1000.0)); } #endif if(theCurrentTime.mSampleTime >= (mAnchorTime.mSampleTime + mFrameCounter)) { // increment the frame counter mFrameCounter += mDevice->GetIOBufferFrameSize(); // the new cycle is starting mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime); if(mDevice->UpdateIOCycleTimingServices()) { // something unexpected happenned with the time stamp, so resynch prior to doing IO AudioTimeStamp theNewAnchor = CAAudioTimeStamp::kZero; theNewAnchor.mSampleTime = 0; theNewAnchor.mHostTime = 0; theNewAnchor.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid; if(mDevice->EstablishIOCycleAnchorTime(theNewAnchor)) { Resynch(&theNewAnchor, false); } else { Resynch(NULL, false); } // re-get the current time too mDevice->GetCurrentTime(theCurrentTime); } // do the IO isInNeedOfResynch = PerformIO(theCurrentTime); } } } else { // calculating the next wake up time failed, so we just stop everything (which // will get picked up when the commands are executed mDevice->ClearAllCommands(); mDevice->Do_StopAllIOProcs(); } // execute any deferred commands mDevice->ExecuteAllCommands(); } } mWorkLoopPhase = kTeardownPhase; mDevice->GetIOCycleTelemetry().IOCycleTeardownBegin(mIOCycleCounter); // the work loop has finished, clear the time constraints ClearTimeConstraints(); // tell the device that the IO thread is torn down mDevice->StopIOCycleTimingServices(); } catch(const CAException& inException) { DebugMessageN1("HP_IOThread::WorkLoop: Caught a CAException, code == %ld", (long int)inException.GetError()); } catch(...) { DebugMessage("HP_IOThread::WorkLoop: Caught an unknown exception."); } // set the device state to know the engine has stopped mDevice->IOEngineStopped(); // Notify clients that the IO thread is stopping. Note that we unlock around this call // due to the fact that clients might want to call back into the HAL. if(wasLocked) { mIOGuard.Unlock(); } // Notify clients that the IO thread is stopping mDevice->PropertiesChanged(1, &theIsRunningAddress); // re-lock the guard wasLocked = mIOGuard.Lock(); mDevice->GetIOCycleTelemetry().IOCycleTeardownEnd(mIOCycleCounter); mWorkLoopPhase = kNotRunningPhase; mIOGuard.NotifyAll(); mIOCycleCounter = 0; if(wasLocked) { mIOGuard.Unlock(); } }
void ZKMORHP_IOThreadSlave::WorkLoopIteration(bool& isInNeedOfResynch) { if (mStopWorkLoop) { WorkLoopTeardown(); return; } try { bool wasLocked = mIOGuard.Lock(); // bool wasLocked; wasLocked = mIOGuard.Try(wasLocked); // get the current time AudioTimeStamp theCurrentTime; mDevice->GetCurrentTime(theCurrentTime); // increment the counter ++mIOCycleCounter; // do IO if the thread wasn't stopped if(!mStopWorkLoop) { if(theCurrentTime.mSampleTime >= (mAnchorTime.mSampleTime + mFrameCounter)) { // increment the frame counter mFrameCounter += mDevice->GetIOBufferFrameSize(); // the new cycle is starting mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime); if(mDevice->UpdateIOCycleTimingServices()) { // something unexpected happened with the time stamp, so resynch prior to doing IO AudioTimeStamp theNewAnchor = CAAudioTimeStamp::kZero; theNewAnchor.mSampleTime = 0; theNewAnchor.mHostTime = 0; theNewAnchor.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid; if(mDevice->EstablishIOCycleAnchorTime(theNewAnchor)) { Resynch(&theNewAnchor, false); } else { Resynch(NULL, false); } // re-get the current time too mDevice->GetCurrentTime(theCurrentTime); } // do the IO isInNeedOfResynch = PerformIO(theCurrentTime); } } // calculate the next wake up time AudioTimeStamp theNextWakeUpTime = CAAudioTimeStamp::kZero; theNextWakeUpTime.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid; // bool wasLocked = false; // bool wasLocked = mIOGuard.Lock(); if(CalculateNextWakeUpTime(theCurrentTime, theNextWakeUpTime, isInNeedOfResynch, wasLocked)) { mDevice->GetIOCycleTelemetry().IOCycleWorkLoopEnd(mIOCycleCounter, theCurrentTime, theNextWakeUpTime); } // execute any deferred commands mDevice->ExecuteAllCommands(); if (wasLocked) mIOGuard.Unlock(); } catch(const CAException& inException) { DebugMessageN1("ZKMORHP_IOThreadSlave::WorkLoopIteration: Caught a CAException, code == %ld", (long int)inException.GetError()); } catch(...) { DebugMessage("ZKMORHP_IOThreadSlave::WorkLoopIteration: Caught an unknown exception."); } }
void HP_IOThread::WorkLoop() { // grab the IO guard bool wasLocked = mIOGuard.Lock(); // initialize some stuff mWorkLoopPhase = kInitializingPhase; mIOCycleCounter = 0; mOverloadCounter = 0; CAPropertyAddress theIsRunningAddress(kAudioDevicePropertyDeviceIsRunning); #if Use_HAL_Telemetry mDevice->GetIOCycleTelemetry().IOCycleInitializeBegin(mIOCycleCounter); #else HAL_IOCYCLEINITIALIZEBEGIN(mIOCycleCounter); #endif try { // and signal that the IO thread is running mIOGuard.NotifyAll(); // initialize the work loop stopping conditions mStopWorkLoop = false; // Tell the device that the IO thread has initialized. Note that we unlock around this call // due to the fact that IOCycleInitialize might not return for a while because it might // have to wait for the hardware to start. if(wasLocked) { mIOGuard.Unlock(); } // tell the device that the IO cycle is initializing to start the timing services mDevice->StartIOCycleTimingServices(); // set the device state to know the engine is running mDevice->IOEngineStarted(); // notify clients that the engine is running mDevice->PropertiesChanged(1, &theIsRunningAddress); // re-lock the guard wasLocked = mIOGuard.Lock(); // make sure the thread is still running before moving on if(!mStopWorkLoop) { // set the time constraints for the IOThread SetTimeConstraints(); // initialize the clock mDevice->EstablishIOCycleAnchorTime(mAnchorTime); mFrameCounter = 0; #if Offset_For_Input if(mDevice->HasInputStreams()) { // the first sleep cycle as to be at least the input safety offset and a buffer's // worth of time to be sure that the input data is all there mFrameCounter += mDevice->GetSafetyOffset(true); } #endif // get the current time AudioTimeStamp theCurrentTime; mDevice->GetCurrentTime(theCurrentTime); // enter the work loop mWorkLoopPhase = kRunningPhase; bool isInNeedOfResynch = false; bool isCheckingForOverloads = false; Float64 theIOBufferFrameSize = mDevice->GetIOBufferFrameSize(); #if Use_HAL_Telemetry mDevice->GetIOCycleTelemetry().IOCycleInitializeEnd(mIOCycleCounter, mAnchorTime); mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime); #else HAL_IOCYCLEINITIALIZEEND(mIOCycleCounter, mAnchorTime); HAL_IOCYCLEWORKLOOPBEGIN(mIOCycleCounter, theCurrentTime); #endif while(!mStopWorkLoop) { // get the new IO buffer frame size Float64 theNewIOBufferFrameSize = mDevice->GetIOBufferFrameSize(); // initialize the next wake up time AudioTimeStamp theNextWakeUpTime = CAAudioTimeStamp::kZero; theNextWakeUpTime.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid; // get the current time mDevice->GetCurrentTime(theCurrentTime); // we have to run a special, untimed IO cycle if the IO buffer size changed if((theNewIOBufferFrameSize != theIOBufferFrameSize) && (theCurrentTime.mSampleTime >= (mAnchorTime.mSampleTime + mFrameCounter))) { // mark the end of the previous cycle #if Use_HAL_Telemetry mDevice->GetIOCycleTelemetry().IOCycleWorkLoopEnd(mIOCycleCounter, theCurrentTime, theNextWakeUpTime); #else HAL_IOCYCLEWORKLOOPEND(mIOCycleCounter, theCurrentTime, theNextWakeUpTime); #endif // increment the cycle counter ++mIOCycleCounter; // increment the frame counter mFrameCounter += theIOBufferFrameSize; // the new cycle is starting #if Use_HAL_Telemetry mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime); #else HAL_IOCYCLEWORKLOOPBEGIN(mIOCycleCounter, theCurrentTime); #endif // do the IO, note that we don't need to update the timing services for this special cycle isInNeedOfResynch = PerformIO(theCurrentTime, theIOBufferFrameSize); // turn off overload checking for the next cycle to be nice to clients isCheckingForOverloads = false; } // calculate the next wake up time if(CalculateNextWakeUpTime(theCurrentTime, theIOBufferFrameSize, theNextWakeUpTime, isCheckingForOverloads, isInNeedOfResynch, wasLocked)) { // sleep until the next wake up time #if Use_HAL_Telemetry mDevice->GetIOCycleTelemetry().IOCycleWorkLoopEnd(mIOCycleCounter, theCurrentTime, theNextWakeUpTime); #else HAL_IOCYCLEWORKLOOPEND(mIOCycleCounter, theCurrentTime, theNextWakeUpTime); #endif mIOGuard.WaitUntil(CAHostTimeBase::ConvertToNanos(theNextWakeUpTime.mHostTime)); // increment the cycle counter ++mIOCycleCounter; // make sure overload checking is enabled isCheckingForOverloads = true; // do IO if the thread wasn't stopped if(!mStopWorkLoop) { // get the current time mDevice->GetCurrentTime(theCurrentTime); if(theCurrentTime.mSampleTime >= (mAnchorTime.mSampleTime + mFrameCounter)) { // increment the frame counter mFrameCounter += theIOBufferFrameSize; // refresh the current buffer size theIOBufferFrameSize = theNewIOBufferFrameSize; // the new cycle is starting #if Use_HAL_Telemetry mDevice->GetIOCycleTelemetry().IOCycleWorkLoopBegin(mIOCycleCounter, theCurrentTime); #else HAL_IOCYCLEWORKLOOPBEGIN(mIOCycleCounter, theCurrentTime); #endif if(mDevice->UpdateIOCycleTimingServices()) { // something unexpected happenned with the time stamp, so resynch prior to doing IO AudioTimeStamp theNewAnchor = CAAudioTimeStamp::kZero; theNewAnchor.mSampleTime = 0; theNewAnchor.mHostTime = 0; theNewAnchor.mFlags = kAudioTimeStampSampleTimeValid + kAudioTimeStampHostTimeValid + kAudioTimeStampRateScalarValid; if(mDevice->EstablishIOCycleAnchorTime(theNewAnchor)) { Resynch(&theNewAnchor, false); } else { Resynch(NULL, false); } // re-get the current time too mDevice->GetCurrentTime(theCurrentTime); // mark the telemetry #if Use_HAL_Telemetry mDevice->GetIOCycleTelemetry().Resynch(GetIOCycleNumber(), mAnchorTime); #else HAL_RESYNCH(GetIOCycleNumber(), mAnchorTime); #endif } // do the IO isInNeedOfResynch = PerformIO(theCurrentTime, theIOBufferFrameSize); } } } else { // calculating the next wake up time failed, so we just stop everything (which // will get picked up when the commands are executed mDevice->ClearAllCommands(); mDevice->Do_StopAllIOProcs(); } // execute any deferred commands mDevice->ExecuteAllCommands(); } } mWorkLoopPhase = kTeardownPhase; #if Use_HAL_Telemetry mDevice->GetIOCycleTelemetry().IOCycleTeardownBegin(mIOCycleCounter); #else HAL_IOCYCLETEARDOWNBEGIN(mIOCycleCounter); #endif // the work loop has finished, clear the time constraints ClearTimeConstraints(); // tell the device that the IO thread is torn down mDevice->StopIOCycleTimingServices(); } catch(const CAException& inException) { DebugMessageN1("HP_IOThread::WorkLoop: Caught a CAException, code == %ld", (long int)inException.GetError()); } catch(...) { DebugMessage("HP_IOThread::WorkLoop: Caught an unknown exception."); } // set the device state to know the engine has stopped mDevice->IOEngineStopped(); // Notify clients that the IO thread is stopping. Note that we unlock around this call // due to the fact that clients might want to call back into the HAL. if(wasLocked) { mIOGuard.Unlock(); } // Notify clients that the IO thread is stopping mDevice->PropertiesChanged(1, &theIsRunningAddress); // re-lock the guard wasLocked = mIOGuard.Lock(); #if Use_HAL_Telemetry mDevice->GetIOCycleTelemetry().IOCycleTeardownEnd(mIOCycleCounter); #else HAL_IOCYCLETEARDOWNEND(mIOCycleCounter); #endif mWorkLoopPhase = kNotRunningPhase; mIOGuard.NotifyAll(); mIOCycleCounter = 0; if(wasLocked) { mIOGuard.Unlock(); } }