LW_NTSTATUS LwRtlSvcmLoadEmbedded( LW_IN LW_PCWSTR pServiceName, LW_IN LW_SVCM_MODULE_ENTRY_FUNCTION Entry, LW_OUT PLW_SVCM_INSTANCE* ppInstance ) { NTSTATUS status = STATUS_SUCCESS; PLW_SVCM_INSTANCE pInstance = NULL; status = InitPool(); GCOS(status); status = LW_RTL_ALLOCATE_AUTO(&pInstance); GCOS(status); LW_RTL_LOG_DEBUG("Loading embedded service: %s", pServiceName); status = LwRtlSvcmInitializeInstance(pInstance, pServiceName, "<embedded>", Entry); GCOS(status); cleanup: if (!NT_SUCCESS(status)) { LwRtlSvcmUnload(pInstance); pInstance = NULL; } *ppInstance = pInstance; return status; }
NTSTATUS RdrCreateContext( PIRP pIrp, PRDR_OP_CONTEXT* ppContext ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContext = NULL; status = LW_RTL_ALLOCATE_AUTO(&pContext); BAIL_ON_NT_STATUS(status); LwListInit(&pContext->Link); pContext->pIrp = pIrp; if (pIrp) { LWIO_LOG_DEBUG("Created op context %p for IRP %p", pContext, pIrp); } else { LWIO_LOG_DEBUG("Created op context %p", pContext); } *ppContext = pContext; error: return status; }
LW_NTSTATUS LwRtlCreateThreadPoolAttributes( LW_OUT PLW_THREAD_POOL_ATTRIBUTES* ppAttrs ) { NTSTATUS status = STATUS_SUCCESS; PLW_THREAD_POOL_ATTRIBUTES pAttrs = NULL; status = LW_RTL_ALLOCATE_AUTO(&pAttrs); GOTO_ERROR_ON_STATUS(status); pAttrs->bDelegateTasks = TRUE; pAttrs->lTaskThreads = 0; pAttrs->lWorkThreads = 0; pAttrs->ulTaskThreadStackSize = (ULONG) _LW_TASK_THREAD_STACK_SIZE; pAttrs->ulWorkThreadStackSize = (ULONG) _LW_WORK_THREAD_STACK_SIZE; pAttrs->ulWorkThreadTimeout = DEFAULT_WORK_THREAD_TIMEOUT; *ppAttrs = pAttrs; cleanup: return status; error: *ppAttrs = NULL; goto cleanup; }
LW_NTSTATUS LwRtlQueueWorkItem( LW_IN PLW_THREAD_POOL pPool, LW_IN LW_WORK_ITEM_FUNCTION_COMPAT pfnFunc, LW_IN LW_PVOID pContext, LW_IN LW_WORK_ITEM_FLAGS Flags ) { NTSTATUS status = STATUS_SUCCESS; PCOMPAT_WORK_ITEM pCompat = NULL; PLW_WORK_ITEM pItem = NULL; status = LW_RTL_ALLOCATE_AUTO(&pCompat); GOTO_ERROR_ON_STATUS(status); pCompat->pfnFunc = pfnFunc; pCompat->pContext = pContext; status = LwRtlCreateWorkItem(pPool, &pItem, CompatWorkItem, pCompat); GOTO_ERROR_ON_STATUS(status); pCompat = NULL; LwRtlScheduleWorkItem(pItem, Flags); pItem = NULL; error: RTL_FREE(&pCompat); LwRtlFreeWorkItem(&pItem); return status; }
NTSTATUS RdrAllocatePacket( ULONG ulSize, PSMB_PACKET* ppPacket ) { NTSTATUS status = STATUS_SUCCESS; PSMB_PACKET pPacket = NULL; status = LW_RTL_ALLOCATE_AUTO(&pPacket); BAIL_ON_NT_STATUS(status); pPacket->refCount = 1; status = RdrAllocatePacketBuffer(pPacket, ulSize); BAIL_ON_NT_STATUS(status); *ppPacket = pPacket; cleanup: return status; error: RdrFreePacket(pPacket); goto cleanup; }
LW_NTSTATUS LwRtlSvcmRefresh( LW_IN PLW_SVCM_INSTANCE pInstance, LW_IN LW_SVCM_NOTIFY_FUNCTION Notify, LW_IN LW_PVOID pContext ) { NTSTATUS status = STATUS_SUCCESS; PSVCM_COMMAND_STATE pRefreshState = NULL; PLW_WORK_ITEM pRefreshItem = NULL; if (!pInstance) { status = STATUS_INVALID_PARAMETER; GCOS(status); } status = LW_RTL_ALLOCATE_AUTO(&pRefreshState); GCOS(status); status = LwRtlCreateWorkItem( gSvcmState.pPool, &pRefreshItem, RefreshWorkItem, pRefreshState); GCOS(status); pRefreshState->pInstance = pInstance; pRefreshState->Notify = Notify; pRefreshState->pNotifyContext = pContext; LwRtlScheduleWorkItem(pRefreshItem, 0); pRefreshItem = NULL; pRefreshState = NULL; cleanup: LwRtlFreeWorkItem(&pRefreshItem); RTL_FREE(&pRefreshState); return status; }
NTSTATUS LwRtlCreateTaskGroup( PLW_THREAD_POOL pPool, PLW_TASK_GROUP* ppGroup ) { NTSTATUS status = STATUS_SUCCESS; PLW_TASK_GROUP pGroup = NULL; if (pPool->pDelegate) { return LwRtlCreateTaskGroup(pPool->pDelegate, ppGroup); } status = LW_RTL_ALLOCATE_AUTO(&pGroup); GOTO_ERROR_ON_STATUS(status); pGroup->pPool = pPool; RingInit(&pGroup->Tasks); status = LwErrnoToNtStatus(pthread_mutex_init(&pGroup->Lock, NULL)); GOTO_ERROR_ON_STATUS(status); pGroup->bLockInit = TRUE; status = LwErrnoToNtStatus(pthread_cond_init(&pGroup->Event, NULL)); GOTO_ERROR_ON_STATUS(status); pGroup->bEventInit = TRUE; *ppGroup = pGroup; cleanup: return status; error: LwRtlFreeTaskGroup(&pGroup); *ppGroup = NULL; goto cleanup; }
LW_NTSTATUS LwRtlSetTaskUnixSignal( LW_IN PLW_TASK pTask, LW_IN int Sig, LW_IN LW_BOOLEAN bSubscribe ) { NTSTATUS status = STATUS_SUCCESS; if (bSubscribe && !pTask->pUnixSignal) { status = LW_RTL_ALLOCATE_AUTO(&pTask->pUnixSignal); GOTO_ERROR_ON_STATUS(status); } status = RegisterTaskUnixSignal(pTask, Sig, bSubscribe); GOTO_ERROR_ON_STATUS(status); error: return status; }
NTSTATUS CreateWorkItem( LW_IN PLW_WORK_THREADS pThreads, LW_OUT PLW_WORK_ITEM* ppWorkItem, LW_WORK_ITEM_FUNCTION pfnFunc, PVOID pContext ) { PLW_WORK_ITEM pItem = NULL; NTSTATUS status = STATUS_SUCCESS; LOCK_THREADS(pThreads); if (pThreads->ulStarted == 0) { /* Make sure at least one thread is running */ status = StartWorkThread(pThreads, &pThreads->pWorkThreads[0]); GOTO_ERROR_ON_STATUS(status); } status = LW_RTL_ALLOCATE_AUTO(&pItem); GOTO_ERROR_ON_STATUS(status); RingInit(&pItem->Ring); pItem->pThreads = pThreads; pItem->pfnFunc = pfnFunc; pItem->pContext = pContext; pThreads->ulWorkItemCount++; error: UNLOCK_THREADS(pThreads); *ppWorkItem = pItem; return status; }
NTSTATUS LwRtlCreateTask( PLW_THREAD_POOL pPool, PLW_TASK* ppTask, PLW_TASK_GROUP pGroup, LW_TASK_FUNCTION pfnFunc, PVOID pContext ) { NTSTATUS status = STATUS_SUCCESS; PEPOLL_TASK pTask = NULL; PEPOLL_THREAD pThread = NULL; ULONG ulMinLoad = 0xFFFFFFFF; ULONG ulIndex = 0; if (pPool->pDelegate) { return LwRtlCreateTask(pPool->pDelegate, ppTask, pGroup, pfnFunc, pContext); } status = LW_RTL_ALLOCATE_AUTO(&pTask); GOTO_ERROR_ON_STATUS(status); RingInit(&pTask->GroupRing); RingInit(&pTask->QueueRing); RingInit(&pTask->SignalRing); pTask->pGroup = pGroup; pTask->ulRefCount = 2; pTask->pfnFunc = pfnFunc; pTask->pFuncContext = pContext; pTask->Fd = -1; pTask->EventArgs = LW_TASK_EVENT_INIT; pTask->EventWait = LW_TASK_EVENT_EXPLICIT; pTask->llDeadline = 0; LOCK_POOL(pPool); for (ulIndex = 0; ulIndex < pPool->ulEventThreadCount; ulIndex++) { if (pPool->pEventThreads[ulIndex].ulLoad < ulMinLoad) { pThread = &pPool->pEventThreads[ulIndex]; ulMinLoad = pThread->ulLoad; } } pTask->pThread = pThread; if (pGroup) { LOCK_GROUP(pGroup); if (pGroup->bCancelled) { UNLOCK_GROUP(pGroup); UNLOCK_POOL(pPool); status = STATUS_CANCELLED; GOTO_ERROR_ON_STATUS(status); } RingInsertBefore(&pGroup->Tasks, &pTask->GroupRing); UNLOCK_GROUP(pGroup); } pThread->ulLoad++; UNLOCK_POOL(pPool); *ppTask = pTask; cleanup: return status; error: if (pTask) { TaskDelete(pTask); } *ppTask = NULL; goto cleanup; }
NTSTATUS LwRtlCreateThreadPool( PLW_THREAD_POOL* ppPool, PLW_THREAD_POOL_ATTRIBUTES pAttrs ) { NTSTATUS status = STATUS_SUCCESS; PLW_THREAD_POOL pPool = NULL; int i = 0; int numCpus = 0; status = LW_RTL_ALLOCATE_AUTO(&pPool); GOTO_ERROR_ON_STATUS(status); status = LwErrnoToNtStatus(pthread_mutex_init(&pPool->Lock, NULL)); GOTO_ERROR_ON_STATUS(status); status = LwErrnoToNtStatus(pthread_cond_init(&pPool->Event, NULL)); GOTO_ERROR_ON_STATUS(status); numCpus = LwRtlGetCpuCount(); if (GetDelegateAttr(pAttrs)) { status = AcquireDelegatePool(&pPool->pDelegate); GOTO_ERROR_ON_STATUS(status); } else { pPool->ulEventThreadCount = GetTaskThreadsAttr(pAttrs, numCpus); if (pPool->ulEventThreadCount) { status = LW_RTL_ALLOCATE_ARRAY_AUTO( &pPool->pEventThreads, pPool->ulEventThreadCount); GOTO_ERROR_ON_STATUS(status); for (i = 0; i < pPool->ulEventThreadCount; i++) { status = InitEventThread(pPool, pAttrs, &pPool->pEventThreads[i], i % numCpus); GOTO_ERROR_ON_STATUS(status); } } } status = InitWorkThreads(&pPool->WorkThreads, pAttrs, numCpus); GOTO_ERROR_ON_STATUS(status); *ppPool = pPool; cleanup: return status; error: LwRtlFreeThreadPool(&pPool); goto cleanup; }
NTSTATUS LwRtlCreateTask( PLW_THREAD_POOL pPool, PLW_TASK* ppTask, PLW_TASK_GROUP pGroup, LW_TASK_FUNCTION pfnFunc, PVOID pContext ) { NTSTATUS status = STATUS_SUCCESS; PSELECT_TASK pTask = NULL; if (pPool->pDelegate) { return LwRtlCreateTask(pPool->pDelegate, ppTask, pGroup, pfnFunc, pContext); } GOTO_ERROR_ON_STATUS(status = LW_RTL_ALLOCATE_AUTO(&pTask)); RingInit(&pTask->GroupRing); RingInit(&pTask->EventRing); pTask->pPool = pPool; pTask->pGroup = pGroup; pTask->ulRefCount = 2; pTask->pfnFunc = pfnFunc; pTask->pFuncContext = pContext; pTask->Fd = -1; pTask->TriggerSet = LW_TASK_EVENT_INIT; pTask->TriggerWait = LW_TASK_EVENT_EXPLICIT; pTask->llDeadline = 0; LOCK_POOL(pPool); if (pGroup) { LOCK_GROUP(pGroup); if (pGroup->bCancelled) { UNLOCK_GROUP(pGroup); UNLOCK_POOL(pPool); status = STATUS_CANCELLED; GOTO_ERROR_ON_STATUS(status); } RingInsertBefore(&pGroup->Tasks, &pTask->GroupRing); } pTask->pThread = &pPool->pEventThreads[pPool->ulNextEventThread]; pPool->ulNextEventThread = (pPool->ulNextEventThread + 1) % pPool->ulEventThreadCount; UNLOCK_POOL(pPool); LOCK_THREAD(pTask->pThread); RingInsertBefore(&pTask->pThread->Tasks, &pTask->EventRing); /* It's not necessary to signal the thread about the new task here since it won't be run anyway */ UNLOCK_THREAD(pTask->pThread); if (pGroup) { UNLOCK_GROUP(pGroup); } *ppTask = pTask; error: return status; }
NTSTATUS LwRtlCreateThreadPool( PLW_THREAD_POOL* ppPool, PLW_THREAD_POOL_ATTRIBUTES pAttrs ) { NTSTATUS status = STATUS_SUCCESS; PLW_THREAD_POOL pPool = NULL; int i = 0; int numCpus = 0; ULONG ulFdLimit = 0; #if defined(_SC_NPROCESSORS_ONLN) numCpus = sysconf(_SC_NPROCESSORS_ONLN); if (numCpus < 0) { numCpus = 1; } #else numCpus = 1; #endif GOTO_ERROR_ON_STATUS(status = LW_RTL_ALLOCATE_AUTO(&pPool)); GOTO_ERROR_ON_STATUS(status = LwErrnoToNtStatus(pthread_mutex_init(&pPool->Lock, NULL))); GOTO_ERROR_ON_STATUS(status = LwErrnoToNtStatus(pthread_cond_init(&pPool->Event, NULL))); if (GetDelegateAttr(pAttrs)) { status = AcquireDelegatePool(&pPool->pDelegate); GOTO_ERROR_ON_STATUS(status); } else { pPool->ulEventThreadCount = GetTaskThreadsAttr(pAttrs, numCpus); pPool->ulNextEventThread = 0; status = GetFdLimit(&ulFdLimit); GOTO_ERROR_ON_STATUS(status); /* * Each thread needs 2 fds for the notification pipe. * This check will limit us to 1/4 of the process fd limit. * This is particularly important on Solaris which has a very * low default limit of 256. */ if (pPool->ulEventThreadCount > ulFdLimit / 8) { pPool->ulEventThreadCount = ulFdLimit / 8; } if (pPool->ulEventThreadCount) { GOTO_ERROR_ON_STATUS(status = LW_RTL_ALLOCATE_ARRAY_AUTO( &pPool->pEventThreads, pPool->ulEventThreadCount)); for (i = 0; i < pPool->ulEventThreadCount; i++) { GOTO_ERROR_ON_STATUS(status = SelectThreadInit(pAttrs, &pPool->pEventThreads[i])); } } } status = InitWorkThreads(&pPool->WorkThreads, pAttrs, numCpus); GOTO_ERROR_ON_STATUS(status); *ppPool = pPool; error: return status; }
LW_NTSTATUS LwRtlSvcmStart( LW_IN PLW_SVCM_INSTANCE pInstance, LW_IN LW_ULONG ArgCount, LW_IN LW_PWSTR* ppArgs, LW_IN LW_ULONG FdCount, LW_IN int* pFds, LW_IN LW_SVCM_NOTIFY_FUNCTION Notify, LW_IN LW_PVOID pContext ) { NTSTATUS status = STATUS_SUCCESS; PSVCM_START_STATE pStartState = NULL; PLW_WORK_ITEM pStartItem = NULL; if (!pInstance) { status = STATUS_INVALID_PARAMETER; GCOS(status); } status = LW_RTL_ALLOCATE_AUTO(&pStartState); GCOS(status); status = LW_RTL_ALLOCATE_AUTO(&pInstance->pStopState); GCOS(status); status = LwRtlCreateWorkItem( gSvcmState.pPool, &pStartItem, StartWorkItem, pStartState); GCOS(status); status = LwRtlCreateWorkItem( gSvcmState.pPool, &pInstance->pStopItem, StopWorkItem, pInstance->pStopState); GCOS(status); pStartState->pInstance = pInstance; pStartState->ArgCount = ArgCount; pStartState->ppArgs = ppArgs; pStartState->FdCount = FdCount; pStartState->pFds = pFds; pStartState->Notify = Notify; pStartState->pNotifyContext = pContext; LwRtlScheduleWorkItem(pStartItem, 0); pStartItem = NULL; pStartState = NULL; cleanup: LwRtlFreeWorkItem(&pStartItem); RTL_FREE(&pStartState); if (status != STATUS_SUCCESS) { RTL_FREE(&pInstance->pStopState); LwRtlFreeWorkItem(&pInstance->pStopItem); } return status; }
NTSTATUS RegisterTaskUnixSignal( LW_IN PLW_TASK pTask, LW_IN int Sig, LW_IN LW_BOOLEAN bSubscribe ) { NTSTATUS status = STATUS_SUCCESS; size_t i = 0; PRING pBase = NULL; PRING pRing = NULL; PLW_SIGNAL_SUBSCRIPTION pExisting = NULL; PLW_SIGNAL_SUBSCRIPTION pSub = NULL; struct sigaction action; #ifdef SIGRTMAX int maxSig = SIGRTMAX; #else int maxSig = SIGUSR2; #endif if (Sig == 0) { for (i = 1; i < maxSig + 1; i++) { status = RegisterTaskUnixSignal(pTask, (int) i, bSubscribe); if (status) { return status; } } return STATUS_SUCCESS; } LOCK_SIGNAL(); if (Sig > maxSig || Sig < 0) { status = STATUS_INVALID_PARAMETER; GOTO_ERROR_ON_STATUS(status); } if (!gSignal.pSubscribers) { status = LW_RTL_ALLOCATE_ARRAY_AUTO(&gSignal.pSubscribers, maxSig + 1); GOTO_ERROR_ON_STATUS(status); for (i = 0; i < maxSig + 1; i++) { RingInit(&gSignal.pSubscribers[i]); } gSignal.maxSig = maxSig; } pBase = &gSignal.pSubscribers[Sig]; for (pRing = pBase->pNext; pRing != pBase; pRing = pRing->pNext) { pSub = LW_STRUCT_FROM_FIELD(pRing, LW_SIGNAL_SUBSCRIPTION, Ring); if (pSub->pTask == pTask) { pExisting = pSub; break; } } if (bSubscribe && !pExisting) { if (Sig != SIGINT) { memset(&action, 0, sizeof(action)); /* Make sure there is a dummy handler for the signal so it is actually delivered to the process */ action.sa_handler = DummyHandler; action.sa_flags = 0; if (sigaction(Sig, &action, NULL) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } } status = LW_RTL_ALLOCATE_AUTO(&pSub); GOTO_ERROR_ON_STATUS(status); pSub->pTask = pTask; pSub->ucRefCount = 1; RingInit(&pSub->Ring); RingInit(&pSub->DispatchRing); RingEnqueue(pBase, &pSub->Ring); RetainTask(pTask); } else if (!bSubscribe && pExisting) { RingRemove(&pExisting->Ring); if (--pExisting->ucRefCount == 0) { LwRtlReleaseTask(&pExisting->pTask); LwRtlMemoryFree(pExisting); } } error: UNLOCK_SIGNAL(); return status; }
LW_NTSTATUS LwRtlSvcmLoadModule( LW_IN LW_PCWSTR pServiceName, LW_IN LW_PCWSTR pModulePath, LW_OUT PLW_SVCM_INSTANCE* ppInstance ) { NTSTATUS status = STATUS_SUCCESS; PLW_SVCM_INSTANCE pInstance = NULL; PSTR pModulePathA = NULL; LW_SVCM_MODULE_ENTRY_FUNCTION Entry = NULL; PSTR pEntryName = NULL; PSTR pBareName = NULL; PSTR pFinalSlash = NULL; PSTR pFinalDot = NULL; status = InitPool(); GCOS(status); status = LwRtlCStringAllocateFromWC16String(&pModulePathA, pModulePath); GCOS(status); pFinalSlash = strrchr(pModulePathA, '/'); pFinalDot = strrchr(pModulePathA, '.'); if (!pFinalSlash) { pFinalSlash = pModulePathA; } else { pFinalSlash++; } if (!pFinalDot) { pFinalDot = pModulePathA + strlen(pModulePathA); } status = LW_RTL_ALLOCATE(&pBareName, CHAR, (pFinalDot - pFinalSlash) + 1); GCOS(status); memcpy(pBareName, pFinalSlash, pFinalDot - pFinalSlash); status = LwRtlCStringAllocatePrintf(&pEntryName, "_LwSvcmEntry_%s", pBareName); GCOS(status); status = LW_RTL_ALLOCATE_AUTO(&pInstance); GCOS(status); LW_RTL_LOG_DEBUG("Loading service module: %s", pModulePathA); (void) dlerror(); pInstance->pDlHandle = dlopen(pModulePathA, RTLD_LOCAL | RTLD_NOW); if (!pInstance->pDlHandle) { LW_RTL_LOG_ERROR( "Could not load service module '%s': %s", pModulePathA, dlerror()); status = LwErrnoToNtStatus(errno); GCOS(status); } (void) dlerror(); Entry = dlsym(pInstance->pDlHandle, pEntryName); if (!Entry) { LW_RTL_LOG_ERROR( "Could not load entry point from service module '%s': %s", pModulePathA, dlerror()); status = LwErrnoToNtStatus(errno); if (!status) { status = STATUS_BAD_DLL_ENTRYPOINT; } GCOS(status); } status = LwRtlSvcmInitializeInstance(pInstance, pServiceName, pModulePathA, Entry); GCOS(status); cleanup: RTL_FREE(&pModulePathA); RTL_FREE(&pBareName); RTL_FREE(&pEntryName); if (!NT_SUCCESS(status)) { LwRtlSvcmUnload(pInstance); pInstance = NULL; } *ppInstance = pInstance; return status; }
static NTSTATUS CreateSocketPair( PLW_TASK_GROUP pGroup, PSOCKET* ppSocket1, PSOCKET* ppSocket2 ) { NTSTATUS status = STATUS_SUCCESS; PSOCKET pSocket1 = NULL; PSOCKET pSocket2 = NULL; int socketFds[2] = {-1, -1}; status = LW_RTL_ALLOCATE_AUTO(&pSocket1); GOTO_ERROR_ON_STATUS(status); status = LW_RTL_ALLOCATE_AUTO(&pSocket2); GOTO_ERROR_ON_STATUS(status); status = LW_RTL_ALLOCATE_ARRAY_AUTO(&pSocket1->pBuffer, gpSettings->ulBufferSize); GOTO_ERROR_ON_STATUS(status); status = LW_RTL_ALLOCATE_ARRAY_AUTO(&pSocket2->pBuffer, gpSettings->ulBufferSize); GOTO_ERROR_ON_STATUS(status); if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketFds) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } pSocket1->Fd = socketFds[0]; pSocket2->Fd = socketFds[1]; pSocket1->State = STATE_SEND; pSocket2->State = STATE_RECV; status = LwRtlCreateTask( gpPool, &pSocket1->pTask, pGroup, Transceiver, pSocket1); GOTO_ERROR_ON_STATUS(status); status = LwRtlCreateTask( gpPool, &pSocket2->pTask, pGroup, Transceiver, pSocket2); GOTO_ERROR_ON_STATUS(status); *ppSocket1 = pSocket1; *ppSocket2 = pSocket2; cleanup: return status; error: goto cleanup; }