HRESULT CNktDvTransportEngine::ConnectAgent(__in DWORD dwPid, __in DWORD dwTimeout) { CNktDvShutdownAutoLock cSdLock(&cShutdownMtx); CNktDvAutoCancellableFastMutex cLock(this, &cShutdownMtx); CConnection *lpConn; HRESULT hRes; if (cLock.IsLockHeld() == FALSE || cShutdownMtx.IsShuttingDown() != FALSE) return NKT_DVERR_Cancelled; if (cShutdownMtx.IsSystemActive() == FALSE) return E_FAIL; //not initialized if (dwPid == 0 || dwPid == dwMePid) return E_INVALIDARG; //check if connection already exists { CConnectionAutoRef cConnAutoRef(lpConn = FindConnectionAndAddRef(dwPid), FALSE); if (lpConn != NULL) return NKT_DVERR_AlreadyExists; } //---- lpConn = NKT_MEMMGR_NEW CConnection(this, dwPid); if (lpConn == NULL) return E_OUTOFMEMORY; //create pipe hRes = lpConn->Initialize(hIOCP, dwTimeout); if (FAILED(hRes)) { lpConn->Release(); return hRes; } //add to connection list cConnList.PushTail(lpConn); return S_OK; }
VOID CNktDvTransportEngine::DispatcherThreadProc(__in SIZE_T nDispatcherPtr) { #define MESSAGES_PER_ROUND 4 CNktThread *lpThread; CNktDvTransportOverlapped *lpOvr[MESSAGES_PER_ROUND]; HANDLE hAvailableEvent; DWORD dwHitEvent; CConnection *lpConn; SIZE_T nProcessed, k, nRetrieved; CDispatcher *lpDispatcher; HRESULT hRes; lpDispatcher = (CDispatcher*)nDispatcherPtr; //---- lpCallback->TEC_WorkerThreadStarted(); //---- lpThread = &(lpDispatcher->cThread); hAvailableEvent = lpDispatcher->hEvent; while (1) { if (lpThread->CheckForAbort(INFINITE, 1, &hAvailableEvent, &dwHitEvent) != FALSE) break; if (dwHitEvent == 1) { ::ResetEvent(hAvailableEvent); //init working NktInterlockedExchange(&(lpDispatcher->nIsWorking), 1); while (lpThread->CheckForAbort(0) == FALSE) { { CNktAutoFastMutex cLock(lpDispatcher); lpOvr[0] = lpDispatcher->PeekNextOverlapped(); if (lpOvr[0] == NULL) break; lpOvr[0]->RemoveNode(); //remove from list //try to get more messages for (nRetrieved=1; nRetrieved<MESSAGES_PER_ROUND; nRetrieved++) { lpOvr[nRetrieved] = lpDispatcher->PeekNextOverlapped(); if (lpOvr[nRetrieved] == NULL || lpOvr[nRetrieved]->sEngineInternals.lpConn != lpOvr[0]->sEngineInternals.lpConn || lpOvr[nRetrieved]->sEngineInternals.dwThreadId != lpOvr[0]->sEngineInternals.dwThreadId) break; if (lpOvr[0]->sMsg.sMsgCommon.dwMsgCode == NKT_DV_TMSG_CODE_BigData) { if (lpOvr[nRetrieved]->sMsg.sMsgCommon.dwMsgCode != NKT_DV_TMSG_CODE_BigData) break; } else { if (lpOvr[nRetrieved]->sMsg.sMsgCommon.dwMsgCode == NKT_DV_TMSG_CODE_BigData) break; } lpOvr[nRetrieved]->RemoveNode(); //remove from list } } //at this point we have up to 'MESSAGES_PER_ROUND' messages to process of the same //connection/tid lpConn = (CConnection*)(lpOvr[0]->sEngineInternals.lpConn); hRes = S_OK; if (lpOvr[0]->sMsg.sMsgCommon.dwMsgCode == NKT_DV_TMSG_CODE_BigData) { CNktAutoFastMutex cConnAutoLock(lpConn); //try to process a sequence of "NKT_DV_TMSG_CODE_BigData" in the same round for (nProcessed=0; nProcessed<nRetrieved && SUCCEEDED(hRes); nProcessed++) { hRes = lpConn->cBigData->ProcessPacket(&(lpOvr[nProcessed]->sMsg.sMsgCommon)); //signal client message event if (SUCCEEDED(hRes)) hRes = SignalProcessedEvent(lpOvr[nProcessed]); //free buffer lpConn->FreeBuffer(lpOvr[nProcessed]); } } else { //try to process a sequence of standard packets for (nProcessed=0; nProcessed<nRetrieved && SUCCEEDED(hRes); nProcessed++) { //process hRes = lpCallback->TEC_OnAgentMessage(this, lpConn->dwPid, &(lpOvr[nProcessed]->sMsg.sMsgCommon), (SIZE_T)(lpOvr[nProcessed]->dwReadedBytes), lpConn->hAgentProc, lpConn->cBigData); //signal client message event if (SUCCEEDED(hRes)) hRes = SignalProcessedEvent(lpOvr[nProcessed]); } //free processed buffers { CNktAutoFastMutex cConnAutoLock(lpConn); for (k=0; k<nProcessed; k++) lpConn->FreeBuffer(lpOvr[k]); } } //if some packets were not processed, it is almost sure that it is because of an error if (nProcessed < nRetrieved) { //requeue non-processed buffers at the front CNktAutoFastMutex cLock(lpDispatcher); for (k=nRetrieved; k>nProcessed; ) lpDispatcher->AddOverlapped(lpOvr[--k], TRUE); } //release connection one for each processed packet from the list for (k=0; k<nProcessed; k++) lpConn->Release(); //handle errors if (FAILED(hRes)) { if (cShutdownMtx.IsSystemActive() != FALSE && cShutdownMtx.IsShuttingDown() == FALSE) lpCallback->TEC_OnTransportError(this, lpConn->dwPid, hRes); DisconnectAgent(lpConn->dwPid); } } //done working NktInterlockedExchange(&(lpDispatcher->nLastWorkTick), (LONG)::GetTickCount()); NktInterlockedExchange(&(lpDispatcher->nIsWorking), 0); } } //---- lpCallback->TEC_WorkerThreadEnded(); #undef MESSAGES_PER_ROUND return; }
VOID CNktDvTransportEngine::WorkerThreadProc(__in SIZE_T nIndex) { CConnection *lpConn; LPOVERLAPPED _lpOvr; CNktDvTransportOverlapped *lpOvr; HRESULT hRes; HANDLE hEventCopy; BOOL b, bReadPending; DWORD dwNumberOfBytes, dwWritten; lpCallback->TEC_WorkerThreadStarted(); //---- for (;;) { lpConn = NULL; lpOvr = NULL; b = ::GetQueuedCompletionStatus(hIOCP, &dwNumberOfBytes, (PULONG_PTR)&lpConn, &_lpOvr, INFINITE); if (lpConn == NULL) { break; //a completion key of 0 is posted to the iocp to request us to shut down... } hRes = (b != FALSE) ? S_OK : NKT_HRESULT_FROM_LASTERROR(); { CConnectionAutoRef cConnAutoRef(lpConn); lpOvr = CNktDvTransportOverlapped::ClassFromOverlapped(_lpOvr); bReadPending = FALSE; if (_lpOvr != NULL) { switch (lpOvr->dwType) { case XTYPE_Read: lpOvr->dwReadedBytes = dwNumberOfBytes; //add to read queue if (SUCCEEDED(hRes)) { lpConn->AddBufferInSortedReadedQueue(lpOvr); hRes = lpConn->SendReadPacket(); //setup read-ahead } NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[ReadCompleted]: Ovr=%IXh, " "hRes=%08X", ::GetTickCount(), lpOvr, hRes)); bReadPending = TRUE; break; case XTYPE_WriteRequest: { CNktAutoFastMutex cLock(lpConn); if (SUCCEEDED(hRes)) lpConn->AddBufferInSortedToWriteQueue(lpOvr); while (SUCCEEDED(hRes) && cShutdownMtx.IsSystemActive() != FALSE && cShutdownMtx.IsShuttingDown() == FALSE) { //get next sequenced block to write lpOvr = lpConn->GetBufferFromSortedToWriteQueue(lpConn->nNextWriteOrderToProcess); if (lpOvr == NULL) break; if (lpOvr->dwType != XTYPE_Discard) { lpConn->AddBufferToRwList(lpOvr); //do real write lpOvr->dwType = XTYPE_Write; if (lpOvr->sMsg.sMsgCommon.hProcessedEvent != NULL) { if (::DuplicateHandle(::GetCurrentProcess(), (HANDLE)(lpOvr->sMsg.sMsgCommon.hProcessedEvent), lpConn->hAgentProc, &hEventCopy, 0, FALSE, DUPLICATE_SAME_ACCESS) != FALSE) lpOvr->sMsg.sMsgCommon.hProcessedEvent = NKT_PTR_2_ULONGLONG(hEventCopy); else hRes = NKT_HRESULT_FROM_LASTERROR(); } if (SUCCEEDED(hRes)) { if (::WriteFile(lpConn->hPipe, &(lpOvr->sMsg), lpOvr->dwWrittenBytes, &dwWritten, &(lpOvr->sOvr)) == FALSE) { hRes = NKT_HRESULT_FROM_LASTERROR(); if (hRes == NKT_HRESULT_FROM_WIN32(ERROR_IO_PENDING)) hRes = S_OK; } } if (SUCCEEDED(hRes)) lpConn->AddRef(); else lpConn->FreeBuffer(lpOvr); NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[Write]: Ovr=%IXh, " "hRes=%08X", ::GetTickCount(), lpOvr, hRes)); } else { lpConn->FreeBuffer(lpOvr); } NktInterlockedIncrement(&(lpConn->nNextWriteOrderToProcess)); } } break; case XTYPE_Write: if (SUCCEEDED(hRes) && lpOvr->dwWrittenBytes != dwNumberOfBytes) hRes = NKT_HRESULT_FROM_WIN32(ERROR_WRITE_FAULT); NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[WriteCompleted]: Ovr=%IXh, " "hRes=%08X", ::GetTickCount(), lpOvr, hRes)); lpConn->FreeBuffer(lpOvr); break; case XTYPE_Discard: lpConn->FreeBuffer(lpOvr); break; default: NKT_ASSERT(FALSE); lpConn->FreeBuffer(lpOvr); break; } } else { hRes = NKT_DVERR_InvalidTransportData; } if (SUCCEEDED(hRes) && bReadPending != FALSE) { while (SUCCEEDED(hRes) && cShutdownMtx.IsSystemActive() != FALSE && cShutdownMtx.IsShuttingDown() == FALSE) { //get next sequenced block readed lpOvr = lpConn->GetBufferFromSortedReadedQueue(lpConn->nNextReadOrderToProcess); if (lpOvr == NULL) break; hRes = DispatchReadedMessage(lpConn, lpOvr); NktInterlockedIncrement(&(lpConn->nNextReadOrderToProcess)); } } if (FAILED(hRes)) { if (cShutdownMtx.IsSystemActive() != FALSE && cShutdownMtx.IsShuttingDown() == FALSE) lpCallback->TEC_OnTransportError(this, lpConn->dwPid, hRes); DisconnectAgent(lpConn->dwPid); } lpConn->Release(); } } //---- lpCallback->TEC_WorkerThreadEnded(); return; }