static VOID DispatchSignal( siginfo_t* pInfo ) { RING dispatch; PRING pBase = NULL; PRING pRing = NULL; PRING pNext = NULL; PLW_SIGNAL_SUBSCRIPTION pSub = NULL; if (!gSignal.pSubscribers || pInfo->si_signo > gSignal.maxSig || pInfo->si_signo < 0) { return; } RingInit(&dispatch); pBase = &gSignal.pSubscribers[pInfo->si_signo]; for (pRing = pBase->pNext; pRing != pBase; pRing = pRing->pNext) { pSub = LW_STRUCT_FROM_FIELD(pRing, LW_SIGNAL_SUBSCRIPTION, Ring); pSub->ucRefCount++; RingInit(&pSub->DispatchRing); RingEnqueue(&dispatch, &pSub->DispatchRing); } UNLOCK_SIGNAL(); for (pRing = dispatch.pNext; pRing != &dispatch; pRing = pRing->pNext) { pSub = LW_STRUCT_FROM_FIELD(pRing, LW_SIGNAL_SUBSCRIPTION, DispatchRing); NotifyTaskUnixSignal(pSub->pTask, pInfo); } LOCK_SIGNAL(); for (pRing = dispatch.pNext; pRing != &dispatch; pRing = pNext) { pNext = pRing->pNext; pSub = LW_STRUCT_FROM_FIELD(pRing, LW_SIGNAL_SUBSCRIPTION, DispatchRing); if (--pSub->ucRefCount == 0) { RingRemove(&pSub->Ring); LwRtlReleaseTask(&pSub->pTask); LwRtlMemoryFree(pSub); } } }
VOID PvfsZctCloseCcb( IN PPVFS_CCB pCcb ) { BOOLEAN bMutexLocked = FALSE; PLW_LIST_LINKS pZctCtxLink = NULL; PLW_LIST_LINKS pNextLink = NULL; PPVFS_ZCT_CONTEXT pZctContext = NULL; LWIO_LOCK_MUTEX(bMutexLocked, &pCcb->FileMutex); pZctCtxLink = PvfsListTraverse(pCcb->pZctContextList, NULL); while (pZctCtxLink) { pZctContext = LW_STRUCT_FROM_FIELD( pZctCtxLink, PVFS_ZCT_CONTEXT, CcbLinks); pNextLink = PvfsListTraverse(pCcb->pZctContextList, pZctCtxLink); PvfsListRemoveItem(pCcb->pZctContextList, pZctCtxLink); pZctCtxLink = pNextLink; PvfsFreeZctContext(&pZctContext); } LWIO_UNLOCK_MUTEX(bMutexLocked, &pCcb->FileMutex); }
VOID LwRtlCancelTaskGroup( PLW_TASK_GROUP group ) { PRING ring = NULL; PLW_TASK pTask = NULL; ULONG i = 0; LOCK_GROUP(group); group->bCancelled = TRUE; for (i = 0; i < group->pPool->ulEventThreadCount; i++) { LOCK_THREAD(&group->pPool->pEventThreads[i]); } for (ring = group->Tasks.pNext; ring != &group->Tasks; ring = ring->pNext) { pTask = LW_STRUCT_FROM_FIELD(ring, SELECT_TASK, GroupRing); pTask->TriggerSet |= LW_TASK_EVENT_EXPLICIT | LW_TASK_EVENT_CANCEL; } for (i = 0; i < group->pPool->ulEventThreadCount; i++) { SignalThread(&group->pPool->pEventThreads[i]); UNLOCK_THREAD(&group->pPool->pEventThreads[i]); } UNLOCK_GROUP(group); }
static PVDIR_PAGED_SEARCH_RECORD VmDirPagedSearchCacheFind( PCSTR pszCookie ) { DWORD dwError = 0; PLW_HASHTABLE_NODE pNode = NULL; PVDIR_PAGED_SEARCH_RECORD pSearchRecord = NULL; BOOLEAN bInLock = FALSE; if (IsNullOrEmptyString(pszCookie)) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER); } VMDIR_LOCK_MUTEX(bInLock, gPagedSearchCache.mutex); dwError = LwRtlHashTableFindKey( gPagedSearchCache.pHashTbl, &pNode, (PVOID)pszCookie); dwError = LwNtStatusToWin32Error(dwError); BAIL_ON_VMDIR_ERROR(dwError); pSearchRecord = LW_STRUCT_FROM_FIELD(pNode, VDIR_PAGED_SEARCH_RECORD, Node); _RefPagedSearchRecord(pSearchRecord); cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gPagedSearchCache.mutex); return pSearchRecord; error: goto cleanup; }
VOID LwRtlWaitTaskGroup( PLW_TASK_GROUP group ) { PRING pRing = NULL; PLW_TASK pTask = NULL; BOOLEAN bStillAlive = TRUE; LOCK_GROUP(group); while (bStillAlive) { bStillAlive = FALSE; for (pRing = group->Tasks.pNext; !bStillAlive && pRing != &group->Tasks; pRing = pRing->pNext) { pTask = LW_STRUCT_FROM_FIELD(pRing, SELECT_TASK, GroupRing); LOCK_THREAD(pTask->pThread); if (pTask->TriggerSet != TASK_COMPLETE_MASK) { bStillAlive = TRUE; } UNLOCK_THREAD(pTask->pThread); } if (bStillAlive) { pthread_cond_wait(&group->Event, &group->Lock); } } UNLOCK_GROUP(group); }
VOID LwRtlCancelTaskGroup( PLW_TASK_GROUP pGroup ) { PRING ring = NULL; PLW_TASK pTask = NULL; LOCK_GROUP(pGroup); pGroup->bCancelled = TRUE; LockAllThreads(pGroup->pPool); for (ring = pGroup->Tasks.pNext; ring != &pGroup->Tasks; ring = ring->pNext) { pTask = LW_STRUCT_FROM_FIELD(ring, EPOLL_TASK, GroupRing); if (pTask->EventSignal != TASK_COMPLETE_MASK) { pTask->EventSignal |= LW_TASK_EVENT_EXPLICIT | LW_TASK_EVENT_CANCEL; RingRemove(&pTask->SignalRing); RingEnqueue(&pTask->pThread->Tasks, &pTask->SignalRing); SignalThread(pTask->pThread); } } UnlockAllThreads(pGroup->pPool); UNLOCK_GROUP(pGroup); }
static VOID ScheduleTimedTasks( PRING pTimed, LONG64 llNow, PRING pRunnable ) { PLW_TASK pTask = NULL; PRING pRing = NULL; PRING pNext = NULL; for (pRing = pTimed->pNext; pRing != pTimed; pRing = pNext) { pNext = pRing->pNext; pTask = LW_STRUCT_FROM_FIELD(pRing, EPOLL_TASK, QueueRing); /* No more tasks in the queue are past the deadline since the queue is sorted */ if (pTask->llDeadline > llNow) { break; } RingRemove(&pTask->QueueRing); RingEnqueue(pRunnable, &pTask->QueueRing); pTask->EventArgs |= LW_TASK_EVENT_TIME; } }
static NTSTATUS PvfsWildcardStackPop( IN OUT PLW_LIST_LINKS pStack, OUT PSTR *ppszInputString, OUT PSTR *ppszPattern ) { NTSTATUS ntError = STATUS_SUCCESS; PLW_LIST_LINKS pStateLink = NULL; PPVFS_WILDCARD_STATE_ENTRY pState = NULL; pStateLink = LwListRemoveAfter(pStack); pState = LW_STRUCT_FROM_FIELD( pStateLink, PVFS_WILDCARD_STATE_ENTRY, StackLinks); *ppszInputString = pState->pszInputString; *ppszPattern = pState->pszPattern; PvfsFreeMemory(OUT_PPVOID(&pState)); return ntError; }
NTSTATUS NpfsFindFCB( PUNICODE_STRING pUnicodeString, PNPFS_FCB * ppFCB ) { NTSTATUS ntStatus = 0; PNPFS_FCB pFCB = NULL; PLW_LIST_LINKS pLink = NULL; for (pLink = gFCBList.Next; pLink != &gFCBList; pLink = pLink->Next) { pFCB = LW_STRUCT_FROM_FIELD(pLink, NPFS_FCB, link); if (RtlUnicodeStringIsEqual(pUnicodeString, &pFCB->PipeName, FALSE)) { NpfsAddRefFCB(pFCB); *ppFCB = pFCB; goto cleanup; } } ntStatus = STATUS_OBJECT_NAME_NOT_FOUND; BAIL_ON_NT_STATUS(ntStatus); cleanup: return(ntStatus); error: *ppFCB = NULL; goto cleanup; }
VOID LsaPcacheReleaseMachinePasswordInfoW( IN PLSA_MACHINE_PASSWORD_INFO_W pPasswordInfo ) { if (pPasswordInfo) { PLSA_MACHINEPWD_CACHE_ENTRY pEntry = LW_STRUCT_FROM_FIELD(pPasswordInfo, LSA_MACHINEPWD_CACHE_ENTRY, PasswordInfoW); LsaPcachepReleaseEntry(pEntry); } }
VOID LsaPcacheReleaseMachineAccountInfoW( IN PLSA_MACHINE_ACCOUNT_INFO_W pAccountInfo ) { if (pAccountInfo) { PLSA_MACHINEPWD_CACHE_ENTRY pEntry = LW_STRUCT_FROM_FIELD(pAccountInfo, LSA_MACHINEPWD_CACHE_ENTRY, PasswordInfoW.Account); LsaPcachepReleaseEntry(pEntry); } }
static LW_PCVOID PagedSearchRecordGetKey( PLW_HASHTABLE_NODE pNode, PVOID pUnused ) { PVDIR_PAGED_SEARCH_RECORD pSearchRecord = NULL; pSearchRecord = LW_STRUCT_FROM_FIELD(pNode, VDIR_PAGED_SEARCH_RECORD, Node); return pSearchRecord->pszGuid; }
static NTSTATUS WorkLoop( PLW_WORK_THREAD pThread ) { NTSTATUS status = STATUS_SUCCESS; PRING pRing = NULL; PLW_WORK_ITEM pItem = NULL; PLW_WORK_THREADS pThreads = pThread->pThreads; LOCK_THREADS(pThread->pThreads); for(;;) { pThreads->ulAvailable++; status = WorkWait(pThread); GOTO_ERROR_ON_STATUS(status); RingDequeue(&pThreads->WorkItems, &pRing); pThreads->ulQueued--; pThreads->ulAvailable--; UNLOCK_THREADS(pThreads); pItem = LW_STRUCT_FROM_FIELD(pRing, LW_WORK_ITEM, Ring); pItem->pfnFunc(pItem, pItem->pContext); LOCK_THREADS(pThreads); } error: pThreads->ulAvailable--; pThreads->ulStarted--; pThread->bStarted = FALSE; /* If the thread pool is not being shut down, nothing is going to call pthread_join() on this thread, so call pthread_detach() now */ if (!pThreads->bShutdown) { pthread_detach(pThread->Thread); pThread->Thread = INVALID_THREAD_HANDLE; } UNLOCK_THREADS(pThreads); return status; }
static VOID ScheduleSignalled( PEPOLL_THREAD pThread, PRING pRunnable, PBOOLEAN pbShutdown ) { PRING pRing = NULL; PRING pNext = NULL; PLW_TASK pTask = NULL; char c = 0; int res = 0; LOCK_THREAD(pThread); if (pThread->bSignalled) { pThread->bSignalled = FALSE; res = read(pThread->SignalFds[0], &c, sizeof(c)); assert(res == sizeof(c)); /* Add all signalled tasks to the runnable list */ for (pRing = pThread->Tasks.pNext; pRing != &pThread->Tasks; pRing = pNext) { pNext = pRing->pNext; pTask = LW_STRUCT_FROM_FIELD(pRing, EPOLL_TASK, SignalRing); RingRemove(&pTask->SignalRing); RingRemove(&pTask->QueueRing); if (pTask->EventSignal != TASK_COMPLETE_MASK) { RingEnqueue(pRunnable, &pTask->QueueRing); /* Transfer the signal bits into the event args */ pTask->EventArgs |= pTask->EventSignal; pTask->EventSignal = 0; } } if (pThread->bShutdown && !*pbShutdown) { *pbShutdown = pThread->bShutdown; } } UNLOCK_THREAD(pThread); }
DWORD LsaAdBatchMarshalList( IN PLSA_AD_PROVIDER_STATE pState, IN PCSTR pszDnsDomainName, IN PCSTR pszNetbiosDomainName, IN OUT PLSA_LIST_LINKS pBatchItemList, IN DWORD dwAvailableCount, OUT PLSA_SECURITY_OBJECT* ppObjects, OUT PDWORD pdwUsedCount ) { DWORD dwError = 0; PLSA_LIST_LINKS pLinks = NULL; DWORD dwIndex = 0; for (pLinks = pBatchItemList->Next; pLinks != pBatchItemList; pLinks = pLinks->Next) { PLSA_AD_BATCH_ITEM pItem = LW_STRUCT_FROM_FIELD(pLinks, LSA_AD_BATCH_ITEM, BatchItemListLinks); if (dwIndex >= dwAvailableCount) { LSA_ASSERT(FALSE); dwError = LW_ERROR_INTERNAL; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaAdBatchMarshal( pState, pszDnsDomainName, pszNetbiosDomainName, pItem, &ppObjects[dwIndex]); BAIL_ON_LSA_ERROR(dwError); if (ppObjects[dwIndex]) { dwIndex++; } } cleanup: *pdwUsedCount = dwIndex; return dwError; error: goto cleanup; }
NTSTATUS NpfsClientCloseHandle( PNPFS_CCB pCCB ) { NTSTATUS ntStatus = 0; PNPFS_PIPE pPipe = NULL; PNPFS_CCB pSCB = NULL; PLW_LIST_LINKS pLink = NULL; PNPFS_IRP_CONTEXT pReadContext = NULL; pPipe = pCCB->pPipe; ENTER_MUTEX(&pPipe->PipeMutex); pSCB = pPipe->pSCB; pPipe->PipeClientState = PIPE_CLIENT_CLOSED; while (pSCB && !LwListIsEmpty(&pSCB->ReadIrpList)) { pLink = pSCB->ReadIrpList.Next; LwListRemove(pLink); pReadContext = LW_STRUCT_FROM_FIELD(pLink, NPFS_IRP_CONTEXT, Link); NpfsServerCompleteReadFile(pSCB, pReadContext); } pthread_cond_signal(&pPipe->PipeCondition); if (pPipe->PipeServerState == PIPE_SERVER_CLOSED) { ntStatus = NpfsFreePipeContext(pPipe); BAIL_ON_NT_STATUS(ntStatus); } error: pPipe->pCCB = NULL; LEAVE_MUTEX(&pPipe->PipeMutex); NpfsReleaseCCB(pCCB); return(ntStatus); }
VOID LwRtlWakeTaskGroup( PLW_TASK_GROUP group ) { PRING ring = NULL; PLW_TASK pTask = NULL; LOCK_GROUP(group); for (ring = group->Tasks.pNext; ring != &group->Tasks; ring = ring->pNext) { pTask = LW_STRUCT_FROM_FIELD(ring, SELECT_TASK, GroupRing); LwRtlWakeTask(pTask); } UNLOCK_GROUP(group); }
static VOID PvfsNotifyFullReportBuffer( PPVFS_FCB pFcb, PPVFS_FCB pReportParentFcb, PPVFS_NOTIFY_REPORT_RECORD pReport ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PLW_LIST_LINKS pFilterLink = NULL; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); for (pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, NULL); pFilterLink; pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, pFilterLink)) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); /* Match the filter and depth */ if ((pFilter->NotifyFilter & pReport->Filter) && ((pFcb == pReportParentFcb) || pFilter->bWatchTree)) { ntError = PvfsNotifyReportBuffer( &pFilter->Buffer, pReport->Action, pReport->pszFilename); break; } } LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); return; }
VOID IopIrpFreeZctIrpList( IN OUT PIO_FILE_OBJECT pFileObject ) { PLW_LIST_LINKS pLinks = NULL;; PIRP_INTERNAL irpInternal = NULL; PIRP pIrp = NULL; while (!LwListIsEmpty(&pFileObject->ZctCompletionIrpList)) { pLinks = LwListRemoveHead(&pFileObject->ZctCompletionIrpList); irpInternal = LW_STRUCT_FROM_FIELD(pLinks, IRP_INTERNAL, CancelLinks); pIrp = &irpInternal->Irp; LWIO_ASSERT(1 == irpInternal->ReferenceCount); LWIO_ASSERT(!pIrp->FileHandle); IopIrpDereference(&pIrp); } }
static NTSTATUS LwIoFindPathCreds( IN PUNICODE_STRING Path, IN BOOLEAN bPrecise, OUT PIO_PATH_CREDS* ppCreds ) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING normalPath = { 0 }; PIO_PATH_CREDS pFoundCreds = NULL; PLW_LIST_LINKS pLink = NULL; status = LwIoNormalizePath(Path, &normalPath); GOTO_CLEANUP_ON_STATUS(status); while ((pLink = LwListTraverse(&gPathCreds, pLink))) { PIO_PATH_CREDS pCreds = LW_STRUCT_FROM_FIELD(pLink, IO_PATH_CREDS, link); if ((bPrecise && LwRtlUnicodeStringIsEqual(&normalPath, &pCreds->PathPrefix, TRUE)) || (!bPrecise && LwRtlUnicodeStringIsPrefix(&pCreds->PathPrefix, &normalPath, TRUE))) { pFoundCreds = pCreds; break; } } cleanup: if (status) { pFoundCreds = NULL; } LwRtlUnicodeStringFree(&normalPath); *ppCreds = pFoundCreds; return status; }
static VOID InsertTimedQueue( PRING pTimed, PLW_TASK pInsert ) { PLW_TASK pTask = NULL; PRING pRing = NULL; /* Find the first task in the queue with a later deadline than the task to insert */ for (pRing = pTimed->pNext; pRing != pTimed; pRing = pRing->pNext) { pTask = LW_STRUCT_FROM_FIELD(pRing, EPOLL_TASK, QueueRing); if (pTask->llDeadline > pInsert->llDeadline) break; } /* Insert the task */ RingInsertBefore(pRing, &pInsert->QueueRing); }
VOID VmDirPagedSearchCacheFree( VOID ) { PLW_HASHTABLE_NODE pNode = NULL; LW_HASHTABLE_ITER iter = LW_HASHTABLE_ITER_INIT; PVDIR_PAGED_SEARCH_RECORD pSearchRecord = NULL; if (gPagedSearchCache.pHashTbl != NULL) { while ((pNode = LwRtlHashTableIterate(gPagedSearchCache.pHashTbl, &iter))) { pSearchRecord = LW_STRUCT_FROM_FIELD(pNode, VDIR_PAGED_SEARCH_RECORD, Node); LwRtlHashTableRemove(gPagedSearchCache.pHashTbl, pNode); VmDirPagedSearchCacheRecordFree(pSearchRecord); } LwRtlFreeHashTable(&gPagedSearchCache.pHashTbl); } VMDIR_SAFE_FREE_MUTEX(gPagedSearchCache.mutex); }
VOID LwRtlWaitTaskGroup( PLW_TASK_GROUP pGroup ) { PRING pRing = NULL; PLW_TASK pTask = NULL; BOOLEAN bStillAlive = TRUE; LOCK_GROUP(pGroup); while (bStillAlive) { bStillAlive = FALSE; LockAllThreads(pGroup->pPool); for (pRing = pGroup->Tasks.pNext; !bStillAlive && pRing != &pGroup->Tasks; pRing = pRing->pNext) { pTask = LW_STRUCT_FROM_FIELD(pRing, EPOLL_TASK, GroupRing); if (pTask->EventSignal != TASK_COMPLETE_MASK) { bStillAlive = TRUE; } } UnlockAllThreads(pGroup->pPool); if (bStillAlive) { pthread_cond_wait(&pGroup->Event, &pGroup->Lock); } } UNLOCK_GROUP(pGroup); }
VOID RdrContinueContextList( PLW_LIST_LINKS pList, NTSTATUS status, PVOID pParam ) { PRDR_OP_CONTEXT pContext = NULL; PLW_LIST_LINKS pLink = NULL; PLW_LIST_LINKS pNext = NULL; for (pLink = pList->Next; pLink != pList; pLink = pNext) { pNext = pLink->Next; pContext = LW_STRUCT_FROM_FIELD(pLink, RDR_OP_CONTEXT, Link); LwListRemove(pLink); if (RdrContinueContext(pContext, status, pParam)) { LwListInsertBefore(pNext, pLink); } } }
static VOID PvfsNotifyCleanIrpList( PVOID pContext ) { PPVFS_IRP_CONTEXT pIrpCtx = (PPVFS_IRP_CONTEXT)pContext; PPVFS_FCB pFcb = NULL; BOOLEAN bFcbLocked = FALSE; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; PLW_LIST_LINKS pFilterLink = NULL; PLW_LIST_LINKS pNextLink = NULL; BOOLEAN bFound = FALSE; LWIO_ASSERT(pIrpCtx->pScb->pOwnerFcb); // We have the IrpCtx->Scb's reference so no need to take another pFcb = pIrpCtx->pScb->pOwnerFcb; LWIO_LOCK_MUTEX(bFcbLocked, &pFcb->BaseControlBlock.Mutex); pFilterLink = PvfsListTraverse(pFcb->pNotifyListIrp, NULL); while (pFilterLink) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); pNextLink = PvfsListTraverse(pFcb->pNotifyListIrp, pFilterLink); if (pFilter->pIrpContext != pIrpCtx) { pFilterLink = pNextLink; continue; } bFound = TRUE; PvfsListRemoveItem(pFcb->pNotifyListIrp, pFilterLink); pFilterLink = NULL; LWIO_UNLOCK_MUTEX(bFcbLocked, &pFcb->BaseControlBlock.Mutex); pFilter->pIrpContext->pIrp->IoStatusBlock.Status = STATUS_CANCELLED; PvfsCompleteIrpContext(pFilter->pIrpContext); PvfsFreeNotifyRecord(&pFilter); /* Can only be one IrpContext match so we are done */ } LWIO_UNLOCK_MUTEX(bFcbLocked, &pFcb->BaseControlBlock.Mutex); if (!bFound) { pIrpCtx->pIrp->IoStatusBlock.Status = STATUS_CANCELLED; PvfsCompleteIrpContext(pIrpCtx); } if (pIrpCtx) { PvfsReleaseIrpContext(&pIrpCtx); } return; }
static VOID PvfsNotifyFullReportIrp( PPVFS_FCB pFcb, PPVFS_FCB pReportParentFcb, PPVFS_NOTIFY_REPORT_RECORD pReport ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PLW_LIST_LINKS pFilterLink = NULL; PLW_LIST_LINKS pNextLink = NULL; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; BOOLEAN bActive = FALSE; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); pFilterLink = PvfsListTraverse(pFcb->pNotifyListIrp, NULL); while(pFilterLink) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); pNextLink = PvfsListTraverse(pFcb->pNotifyListIrp, pFilterLink); /* Continue if we don't match the filter and depth */ if (!((pFilter->NotifyFilter & pReport->Filter) && ((pFcb == pReportParentFcb) || pFilter->bWatchTree))) { pFilter = NULL; pFilterLink = pNextLink; continue; } PvfsListRemoveItem(pFcb->pNotifyListIrp, pFilterLink); LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); pFilterLink = NULL; PvfsQueueCancelIrpIfRequested(pFilter->pIrpContext); bActive = PvfsIrpContextMarkIfNotSetFlag( pFilter->pIrpContext, PVFS_IRP_CTX_FLAG_CANCELLED, PVFS_IRP_CTX_FLAG_ACTIVE); if (!bActive) { PvfsFreeNotifyRecord(&pFilter); pFilterLink = pNextLink; continue; } ntError = PvfsNotifyReportIrp( pFilter->pIrpContext, pReport->Action, pReport->pszFilename); BAIL_ON_NT_STATUS(ntError); /* If we have been asked to buffer changes, move the Fitler Record to the buffer list */ if (pFilter->Buffer.Length > 0) { LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); ntError = PvfsListAddTail(pFcb->pNotifyListBuffer, pFilterLink); LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); BAIL_ON_NT_STATUS(ntError); pFilter = NULL; } /* We only process on matching IRP */ break; } cleanup: LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); if (pFilter) { PvfsFreeNotifyRecord(&pFilter); } return; error: goto cleanup; }
static NTSTATUS ProcessRunnable( PEPOLL_THREAD pThread, PRING pRunnable, PRING pTimed, PRING pWaiting, LONG64 llNow ) { NTSTATUS status = STATUS_SUCCESS; ULONG ulTicks = MAX_TICKS; PLW_TASK pTask = NULL; PLW_TASK_GROUP pGroup = NULL; PRING pRing = NULL; PRING pNext = NULL; /* We are guaranteed to run each task at least once. If tasks remain on the runnable list by yielding, we will continue to run them all in a round robin until our ticks are depleted. */ while (ulTicks && !RingIsEmpty(pRunnable)) { for (pRing = pRunnable->pNext; pRing != pRunnable; pRing = pNext) { pNext = pRing->pNext; pTask = LW_STRUCT_FROM_FIELD(pRing, EPOLL_TASK, QueueRing); RunTask(pTask, llNow); if (ulTicks) { ulTicks--; } if (pTask->EventWait != LW_TASK_EVENT_COMPLETE) { /* Task is still waiting to be runnable, update events in epoll set */ status = UpdateEventWait( pTask, pThread->EpollFd ); GOTO_ERROR_ON_STATUS(status); if (pTask->EventWait & LW_TASK_EVENT_YIELD) { /* Task is yielding. Set YIELD in its trigger arguments and and leave it on the runnable list for the next iteration */ pTask->EventArgs |= LW_TASK_EVENT_YIELD; } else if (pTask->EventWait & LW_TASK_EVENT_TIME) { /* If the task is waiting for a timeout, insert it into the timed queue */ RingRemove(&pTask->QueueRing); InsertTimedQueue(pTimed, pTask); } else { /* Otherwise, put it in the generic waiting queue */ RingRemove(&pTask->QueueRing); RingEnqueue(pWaiting, &pTask->QueueRing); } } else { /* Task is complete */ RingRemove(&pTask->QueueRing); /* Turn off any fd in the epoll set */ if (pTask->Fd >= 0) { status = LwRtlSetTaskFd(pTask, pTask->Fd, 0); GOTO_ERROR_ON_STATUS(status); } /* Unsubscribe task from any UNIX signals */ if (pTask->pUnixSignal) { RegisterTaskUnixSignal(pTask, 0, FALSE); } LOCK_POOL(pThread->pPool); pThread->ulLoad--; UNLOCK_POOL(pThread->pPool); pGroup = pTask->pGroup; /* If task was in a task group, remove it and notify anyone waiting on the group */ if (pGroup) { LOCK_GROUP(pGroup); pTask->pGroup = NULL; RingRemove(&pTask->GroupRing); pthread_cond_broadcast(&pGroup->Event); UNLOCK_GROUP(pGroup); } LOCK_THREAD(pThread); if (--pTask->ulRefCount) { /* The task still has a reference, so mark it as completed and notify anyone waiting on it */ pTask->EventSignal = TASK_COMPLETE_MASK; pthread_cond_broadcast(&pThread->Event); UNLOCK_THREAD(pThread); } else { /* We held the last reference to the task, so delete it */ RingRemove(&pTask->SignalRing); UNLOCK_THREAD(pThread); TaskDelete(pTask); } } } } error: return status; }
static NTSTATUS PvfsNotifyReportBufferedChanges( PPVFS_CCB pCcb, PPVFS_FCB pFcb, PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; FILE_NOTIFY_CHANGE Filter = pIrpContext->pIrp->Args.ReadDirectoryChange.NotifyFilter; PVOID pBuffer = pIrpContext->pIrp->Args.ReadDirectoryChange.Buffer; ULONG Length = pIrpContext->pIrp->Args.ReadDirectoryChange.Length; PLW_LIST_LINKS pFilterLink = NULL; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); /* See if we have any changes to report immediately */ for (pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, NULL); pFilterLink; pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, pFilterLink)) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); /* To return the buffered changes, we have to match the handle and the filter */ if ((pFilter->NotifyFilter != Filter) || (pFilter->pCcb != pCcb)) { continue; } /* We have a match to check to see if we have anything */ if ((pFilter->Buffer.Length == 0) || (pFilter->Buffer.Offset == 0)) { ntError = STATUS_NOT_FOUND; BAIL_ON_NT_STATUS(ntError); } /* We have changes....Do we have enough space? Have we already overflowed the buffer? */ ntError = pFilter->Buffer.Status; BAIL_ON_NT_STATUS(ntError); if (pFilter->Buffer.Offset > Length) { PvfsNotifyClearBufferedChanges(&pFilter->Buffer); ntError = STATUS_NOTIFY_ENUM_DIR; BAIL_ON_NT_STATUS(ntError); } memcpy(pBuffer, pFilter->Buffer.pData, pFilter->Buffer.Offset); pIrpContext->pIrp->IoStatusBlock.BytesTransferred = pFilter->Buffer.Offset; PvfsNotifyClearBufferedChanges(&pFilter->Buffer); } if (pFilterLink == NULL) { ntError = STATUS_NOT_FOUND; BAIL_ON_NT_STATUS(ntError); } cleanup: LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); return ntError; error: goto cleanup; }
static NTSTATUS EventLoop( PEPOLL_THREAD pThread ) { NTSTATUS status = STATUS_SUCCESS; RING timed; RING runnable; RING waiting; CLOCK clock = {0}; LONG64 llNow = 0; LONG64 llNextDeadline = 0; struct epoll_event events[MAX_EVENTS]; int ready = 0; BOOLEAN bShutdown = FALSE; BOOLEAN bSignalled = FALSE; RingInit(&runnable); RingInit(&timed); RingInit(&waiting); for (;;) { /* Get current time for this iteration */ status = ClockGetMonotonicTime(&clock, &llNow); GOTO_ERROR_ON_STATUS(status); /* Schedule any timed tasks that have reached their deadline */ ScheduleTimedTasks( &timed, llNow, &runnable); /* Schedule any waiting tasks that epoll indicated are ready and check if the thread received a signal */ ScheduleWaitingTasks( events, ready, llNow, &runnable, &bSignalled); if (bSignalled) { /* Schedule explicitly-signalled tasks and check if we have been told to shut down */ ScheduleSignalled( pThread, &runnable, &bShutdown); } /* Process runnable tasks */ status = ProcessRunnable( pThread, &runnable, &timed, &waiting, llNow); GOTO_ERROR_ON_STATUS(status); if (!RingIsEmpty(&runnable)) { /* If there are still runnable tasks, set the next deadline to now so we can check for other tasks becoming runnable but do not block in Poll() */ llNextDeadline = llNow; } else if (!RingIsEmpty(&timed)) { /* There are timed tasks, so set our next deadline to the deadline of the first task in the queue */ llNextDeadline = LW_STRUCT_FROM_FIELD(timed.pNext, EPOLL_TASK, QueueRing)->llDeadline; } else if (!RingIsEmpty(&waiting) || !bShutdown) { /* There are waiting tasks or we are not shutting down, so poll indefinitely */ llNextDeadline = -1; } else { /* We are shutting down and there are no remaining tasks, so leave */ break; } /* Wait (or check) for activity */ status = Poll( &clock, &llNow, pThread->EpollFd, events, MAX_EVENTS, llNextDeadline, &ready); GOTO_ERROR_ON_STATUS(status); } error: return status; }
static NTSTATUS EventLoop( PSELECT_THREAD pThread ) { NTSTATUS status = STATUS_SUCCESS; RING tasks; RING runnable; PRING pRing = NULL; PRING pNext = NULL; PSELECT_TASK pTask = NULL; CLOCK clock = {0}; LONG64 llNow; LONG64 llNextDeadline; fd_set readSet; fd_set writeSet; fd_set exceptSet; int ready = 0; int nfds = 0; char c = 0; int res = 0; BOOLEAN bShutdown = FALSE; PLW_TASK_GROUP pGroup = NULL; BOOLEAN bYielding = FALSE; RingInit(&tasks); RingInit(&runnable); FD_ZERO(&readSet); FD_ZERO(&writeSet); FD_ZERO(&exceptSet); LOCK_THREAD(pThread); while (!bShutdown || !RingIsEmpty(&tasks)) { /* Reset variables */ llNextDeadline = 0; nfds = 0; bYielding = FALSE; /* Get current time for this iteration */ GOTO_ERROR_ON_STATUS(status = ClockGetMonotonicTime(&clock, &llNow)); /* Figure out which tasks are runnable */ for (pRing = tasks.pNext; pRing != &tasks; pRing = pNext) { pNext = pRing->pNext; pTask = LW_STRUCT_FROM_FIELD(pRing, SELECT_TASK, EventRing); /* Update trigger set with results from select() */ UpdateTriggerSet( pTask, &readSet, &writeSet, &exceptSet, llNow); /* Schedule tasks to run if they have been triggered or were yielding */ if ((pTask->TriggerWait & LW_TASK_EVENT_YIELD) || ((pTask->TriggerWait | LW_TASK_EVENT_EXPLICIT) & pTask->TriggerSet)) { /* Put task on a separate list to run its trigger function */ RingRemove(&pTask->EventRing); RingInsertBefore(&runnable, &pTask->EventRing); /* Update the trigger args with the trigger set */ pTask->TriggerArgs |= pTask->TriggerSet; /* Turn off bits (except cancel) now that we have copied them */ pTask->TriggerSet &= (LW_TASK_EVENT_CANCEL); } else { /* Update select parameters to wait for task to trigger */ UpdateTriggerWait( pTask, &nfds, &readSet, &writeSet, &exceptSet, &llNextDeadline); } } UNLOCK_THREAD(pThread); for (pRing = runnable.pNext; pRing != &runnable; pRing = pNext) { pNext = pRing->pNext; pTask = LW_STRUCT_FROM_FIELD(pRing, SELECT_TASK, EventRing); GOTO_ERROR_ON_STATUS(status = TaskProcessTrigger(pTask, llNow)); if (pTask->TriggerWait != 0) { /* Task is still waiting to be runnable, update select parameters and put it back in the task list */ UpdateTriggerWait( pTask, &nfds, &readSet, &writeSet, &exceptSet, &llNextDeadline); if (pTask->TriggerWait & LW_TASK_EVENT_YIELD) { /* Task is yielding temporarily. Set the yield flag on its trigger arguments. Leave it on the runnable list */ pTask->TriggerArgs |= LW_TASK_EVENT_YIELD; } else { RingRemove(&pTask->EventRing); RingInsertBefore(&tasks, &pTask->EventRing); } } else { /* Task is complete, notify and remove from task group if it is in one */ RingRemove(&pTask->EventRing); /* Unregister task from global signal loop */ if (pTask->pUnixSignal) { RegisterTaskUnixSignal(pTask, 0, FALSE); } pGroup = pTask->pGroup; if (pGroup) { LOCK_GROUP(pGroup); pTask->pGroup = NULL; RingRemove(&pTask->GroupRing); pthread_cond_broadcast(&pGroup->Event); UNLOCK_GROUP(pGroup); } LOCK_THREAD(pThread); if (--pTask->ulRefCount) { pTask->TriggerSet = TASK_COMPLETE_MASK; pthread_cond_broadcast(&pThread->Event); UNLOCK_THREAD(pThread); } else { UNLOCK_THREAD(pThread); TaskDelete(pTask); } } } if (!RingIsEmpty(&runnable)) { /* We have runnable tasks that are yielding. Move them back to the event list and note the fact. */ bYielding = TRUE; RingMove(&runnable, &tasks); } if (!bShutdown) { /* Also wait for a poke on the thread's signal fd */ FD_SET(pThread->SignalFds[0], &readSet); if (pThread->SignalFds[0] >= nfds) { nfds = pThread->SignalFds[0] + 1; } } if (nfds) { /* If there are still runnable tasks due to LW_TASK_EVENT_YIELD, set the next deadline to now so we wake immediately. This gives other tasks the chance to become runnable before we proceed */ if (bYielding) { llNextDeadline = llNow; } /* Wait for a task to be runnable */ GOTO_ERROR_ON_STATUS(status = Sleep( &clock, &llNow, nfds, &readSet, &writeSet, &exceptSet, llNextDeadline, &ready)); } LOCK_THREAD(pThread); /* Check for a signal to the thread */ if (FD_ISSET(pThread->SignalFds[0], &readSet)) { FD_CLR(pThread->SignalFds[0], &readSet); pThread->bSignalled = FALSE; res = read(pThread->SignalFds[0], &c, sizeof(c)); assert(res == sizeof(c)); /* Move all tasks in queue into local task list */ RingMove(&pThread->Tasks, &tasks); if (pThread->bShutdown && !bShutdown) { bShutdown = pThread->bShutdown; /* Cancel all outstanding tasks */ for (pRing = tasks.pNext; pRing != &tasks; pRing = pRing->pNext) { pTask = LW_STRUCT_FROM_FIELD(pRing, SELECT_TASK, EventRing); pTask->TriggerSet |= LW_TASK_EVENT_CANCEL | LW_TASK_EVENT_EXPLICIT; } } } } error: UNLOCK_THREAD(pThread); return status; }