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); } } }
Res ThreadRegister(Thread *threadReturn, Arena arena) { Res res; Thread thread; Ring ring; void *p; AVER(threadReturn != NULL); res = ControlAlloc(&p, arena, sizeof(ThreadStruct), /* withReservoirPermit */ FALSE); if(res != ResOK) return res; thread = (Thread)p; thread->arena = arena; RingInit(&thread->arenaRing); thread->sig = ThreadSig; thread->serial = arena->threadSerial; ++arena->threadSerial; AVERT(Thread, thread); ring = ArenaThreadRing(arena); AVER(RingCheckSingle(ring)); /* .single */ RingAppend(ring, &thread->arenaRing); *threadReturn = thread; return ResOK; }
Res ThreadRegister(Thread *threadReturn, Arena arena) { Res res; Thread thread; Ring ring; void *p; AVER(threadReturn != NULL); res = ControlAlloc(&p, arena, sizeof(ThreadStruct)); if (res != ResOK) return res; thread = (Thread)p; thread->arena = arena; RingInit(&thread->arenaRing); thread->serial = arena->threadSerial; ++arena->threadSerial; thread->alive = TRUE; thread->forking = FALSE; thread->port = mach_thread_self(); AVER(MACH_PORT_VALID(thread->port)); thread->sig = ThreadSig; AVERT(Thread, thread); ProtThreadRegister(); ring = ArenaThreadRing(arena); RingAppend(ring, &thread->arenaRing); *threadReturn = thread; return ResOK; }
Res ThreadRegister(Thread *threadReturn, Arena arena) { Res res; Thread thread; void *p; AVER(threadReturn != NULL); AVERT(Arena, arena); res = ControlAlloc(&p, arena, sizeof(ThreadStruct), /* withReservoirPermit */ FALSE); if(res != ResOK) return res; thread = (Thread)p; thread->id = pthread_self(); RingInit(&thread->arenaRing); thread->sig = ThreadSig; thread->serial = arena->threadSerial; ++arena->threadSerial; thread->arena = arena; thread->mfc = NULL; PThreadextInit(&thread->thrextStruct, thread->id); AVERT(Thread, thread); RingAppend(ArenaThreadRing(arena), &thread->arenaRing); *threadReturn = thread; return ResOK; }
static void rememberedSummaryBlockInit(struct RememberedSummaryBlockStruct *block) { size_t i; RingInit(&block->globalRing); for(i = 0; i < RememberedSummaryBLOCK; ++ i) { block->the[i].base = (Addr)0; block->the[i].summary = RefSetUNIV; } }
static Res BufferAbsInit(Buffer buffer, Pool pool, Bool isMutator, ArgList args) { Arena arena; AVER(buffer != NULL); AVERT(Pool, pool); AVER(BoolCheck(isMutator)); AVERT(ArgList, args); /* Superclass init */ InstInit(CouldBeA(Inst, buffer)); arena = PoolArena(pool); /* Initialize the buffer. See <code/mpmst.h> for a definition of the structure. sig and serial comes later .init.sig-serial */ buffer->arena = arena; buffer->pool = pool; RingInit(&buffer->poolRing); buffer->isMutator = isMutator; if (ArenaGlobals(arena)->bufferLogging) { buffer->mode = BufferModeLOGGED; } else { buffer->mode = 0; } buffer->fillSize = 0.0; buffer->emptySize = 0.0; buffer->alignment = PoolAlignment(pool); buffer->base = (Addr)0; buffer->initAtFlip = (Addr)0; /* In the next three assignments we really mean zero, not NULL, because the bit pattern is compared. It's pretty unlikely we'll encounter a platform where this makes a difference. */ buffer->ap_s.init = (mps_addr_t)0; buffer->ap_s.alloc = (mps_addr_t)0; buffer->ap_s.limit = (mps_addr_t)0; buffer->poolLimit = (Addr)0; buffer->rampCount = 0; /* .init.sig-serial: Now the vanilla stuff is initialized, sign the buffer and give it a serial number. It can then be safely checked in subclass methods. */ buffer->serial = pool->bufferSerial; /* .trans.mod */ ++pool->bufferSerial; SetClassOfPoly(buffer, CLASS(Buffer)); buffer->sig = BufferSig; AVERT(Buffer, buffer); /* Attach the initialized buffer to the pool. */ RingAppend(&pool->bufferRing, &buffer->poolRing); EVENT3(BufferInit, buffer, pool, BOOLOF(buffer->isMutator)); return ResOK; }
static NTSTATUS SelectThreadInit( PLW_THREAD_POOL_ATTRIBUTES pAttrs, PSELECT_THREAD pThread ) { NTSTATUS status = STATUS_SUCCESS; pthread_attr_t pthreadAttr; BOOLEAN bAttrInit = FALSE; status = LwErrnoToNtStatus(pthread_attr_init(&pthreadAttr)); GOTO_ERROR_ON_STATUS(status); bAttrInit = TRUE; GOTO_ERROR_ON_STATUS(status = LwErrnoToNtStatus(pthread_mutex_init(&pThread->Lock, NULL))); GOTO_ERROR_ON_STATUS(status = LwErrnoToNtStatus(pthread_cond_init(&pThread->Event, NULL))); if (pipe(pThread->SignalFds) < 0) { GOTO_ERROR_ON_STATUS(status = LwErrnoToNtStatus(errno)); } SetCloseOnExec(pThread->SignalFds[0]); SetCloseOnExec(pThread->SignalFds[1]); RingInit(&pThread->Tasks); if (pAttrs && pAttrs->ulTaskThreadStackSize) { GOTO_ERROR_ON_STATUS(status = LwErrnoToNtStatus( pthread_attr_setstacksize(&pthreadAttr, pAttrs->ulTaskThreadStackSize))); } GOTO_ERROR_ON_STATUS(status = LwErrnoToNtStatus( pthread_create( &pThread->Thread, &pthreadAttr, EventThread, pThread))); error: if (bAttrInit) { pthread_attr_destroy(&pthreadAttr); } return status; }
static void EPVMSaveInit(EPVM epvm, Index level) { EPVMSave save = EPVMLevelSave(epvm, level); RingInit(&save->segRing); save->epvm = epvm; save->level = level; save->size = 0; save->smallStringSeg = FALSE; save->smallObjectSeg = FALSE; save->sig = EPVMSaveSig; /* .save.nocheck: Can't be checked before the pool init is */ /* completed, then it is checked by EPVMCheck. */ }
void PageInit(Chunk chunk, Index pi) { Page page; AVERT_CRITICAL(Chunk, chunk); AVER_CRITICAL(pi < chunk->pages); page = ChunkPage(chunk, pi); BTRes(chunk->allocTable, pi); PageSetPool(page, NULL); PageSetType(page, PageStateFREE); RingInit(PageSpareRing(page)); }
NTSTATUS InitWorkThreads( PLW_WORK_THREADS pThreads, PLW_THREAD_POOL_ATTRIBUTES pAttrs, int numCpus ) { NTSTATUS status = STATUS_SUCCESS; size_t i = 0; RingInit(&pThreads->WorkItems); status = LwErrnoToNtStatus(pthread_mutex_init(&pThreads->Lock, NULL)); GOTO_ERROR_ON_STATUS(status); pThreads->bDestroyLock = TRUE; status = LwErrnoToNtStatus(pthread_cond_init(&pThreads->Event, NULL)); GOTO_ERROR_ON_STATUS(status); pThreads->bDestroyEvent = TRUE; pThreads->ulWorkThreadCount = GetWorkThreadsAttr(pAttrs, numCpus); pThreads->ulWorkThreadStackSize = pAttrs ? pAttrs->ulWorkThreadStackSize : 0; pThreads->ulWorkThreadTimeout = GetWorkThreadTimeoutAttr(pAttrs); if (pThreads->ulWorkThreadCount) { status = LW_RTL_ALLOCATE_ARRAY_AUTO( &pThreads->pWorkThreads, pThreads->ulWorkThreadCount); GOTO_ERROR_ON_STATUS(status); for (i = 0; i < pThreads->ulWorkThreadCount; i++) { pThreads->pWorkThreads[i].Thread = INVALID_THREAD_HANDLE; } } if (pThreads->ulWorkThreadTimeout == 0) { for (i = 0; i < pThreads->ulWorkThreadCount; i++) { status = StartWorkThread(pThreads, &pThreads->pWorkThreads[i]); GOTO_ERROR_ON_STATUS(status); } } error: return status; }
Res ThreadRegister(Thread *threadReturn, Arena arena) { Res res; Thread thread; HANDLE procHandle; BOOL b; void *p; AVER(threadReturn != NULL); AVERT(Arena, arena); res = ControlAlloc(&p, arena, sizeof(ThreadStruct), /* withReservoirPermit */ FALSE); if(res != ResOK) return res; thread = (Thread)p; /* avoid pun */ /* Duplicate handle gives us a new handle with updated privileges. * .thread.handle describes the ones needed. */ procHandle = GetCurrentProcess(); b = DuplicateHandle(procHandle, GetCurrentThread(), procHandle, &thread->handle, THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT, FALSE, 0); if(!b) return ResRESOURCE; thread->id = GetCurrentThreadId(); RingInit(&thread->arenaRing); thread->sig = ThreadSig; thread->serial = arena->threadSerial; ++arena->threadSerial; thread->arena = arena; AVERT(Thread, thread); RingAppend(ArenaThreadRing(arena), &thread->arenaRing); *threadReturn = thread; return ResOK; }
static Res SegAbsInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) { Arena arena; Addr addr, limit; Tract tract; AVER(seg != NULL); AVERT(Pool, pool); arena = PoolArena(pool); AVER(AddrIsArenaGrain(base, arena)); AVER(SizeIsArenaGrains(size, arena)); AVERT(ArgList, args); NextMethod(Inst, Seg, init)(CouldBeA(Inst, seg)); limit = AddrAdd(base, size); seg->limit = limit; seg->rankSet = RankSetEMPTY; seg->white = TraceSetEMPTY; seg->nailed = TraceSetEMPTY; seg->grey = TraceSetEMPTY; seg->pm = AccessSetEMPTY; seg->sm = AccessSetEMPTY; seg->defer = WB_DEFER_INIT; seg->depth = 0; seg->queued = FALSE; seg->firstTract = NULL; RingInit(SegPoolRing(seg)); TRACT_FOR(tract, addr, arena, base, limit) { AVERT(Tract, tract); AVER(TractP(tract) == NULL); AVER(!TractHasSeg(tract)); AVER(TractPool(tract) == pool); AVER(TractWhite(tract) == TraceSetEMPTY); TRACT_SET_SEG(tract, seg); if (addr == base) { AVER(seg->firstTract == NULL); seg->firstTract = tract; } AVER(seg->firstTract != NULL); }
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; }
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; }
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 InitEventThread( PEPOLL_POOL pPool, PLW_THREAD_POOL_ATTRIBUTES pAttrs, PEPOLL_THREAD pThread, ULONG ulCpu ) { NTSTATUS status = STATUS_SUCCESS; struct epoll_event event; pthread_attr_t threadAttr; BOOLEAN bThreadAttrInit = FALSE; status = LwErrnoToNtStatus(pthread_attr_init(&threadAttr)); GOTO_ERROR_ON_STATUS(status); bThreadAttrInit = TRUE; pThread->pPool = pPool; status = LwErrnoToNtStatus(pthread_mutex_init(&pThread->Lock, NULL)); GOTO_ERROR_ON_STATUS(status); status = LwErrnoToNtStatus(pthread_cond_init(&pThread->Event, NULL)); GOTO_ERROR_ON_STATUS(status); if (pipe(pThread->SignalFds) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } SetCloseOnExec(pThread->SignalFds[0]); SetCloseOnExec(pThread->SignalFds[1]); if ((pThread->EpollFd = epoll_create(MAX_EVENTS)) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } SetCloseOnExec(pThread->EpollFd); memset(&event, 0, sizeof(event)); /* Add signal fd to epoll set */ event.events = EPOLLIN; event.data.ptr = NULL; if (epoll_ctl(pThread->EpollFd, EPOLL_CTL_ADD, pThread->SignalFds[0], &event) < 0) { ABORT_ON_FATAL_ERRNO(errno); status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } RingInit(&pThread->Tasks); status = LwRtlSetAffinityThreadAttribute(&threadAttr, ulCpu); GOTO_ERROR_ON_STATUS(status); if (pAttrs && pAttrs->ulTaskThreadStackSize) { status = LwErrnoToNtStatus( pthread_attr_setstacksize(&threadAttr, pAttrs->ulTaskThreadStackSize)); GOTO_ERROR_ON_STATUS(status); } status = LwErrnoToNtStatus( pthread_create( &pThread->Thread, &threadAttr, EventThread, pThread)); GOTO_ERROR_ON_STATUS(status); error: if (bThreadAttrInit) { pthread_attr_destroy(&threadAttr); } 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; 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; }
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; }
void (RingInit)(Ring ring) { RingInit(ring); /* <code/mpm.h#ring.init> */ }
Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved, BootBlock boot) { Size size; Count pages; Shift pageShift; Size pageTableSize; Addr allocBase; void *p; Res res; /* chunk is supposed to be uninitialized, so don't check it. */ AVERT(Arena, arena); AVER(base != NULL); AVER(AddrIsAligned(base, ArenaGrainSize(arena))); AVER(base < limit); AVER(AddrIsAligned(limit, ArenaGrainSize(arena))); AVERT(BootBlock, boot); chunk->serial = (arena->chunkSerial)++; chunk->arena = arena; RingInit(&chunk->arenaRing); chunk->pageSize = ArenaGrainSize(arena); chunk->pageShift = pageShift = SizeLog2(chunk->pageSize); chunk->base = base; chunk->limit = limit; chunk->reserved = reserved; size = ChunkSize(chunk); /* .overhead.pages: Chunk overhead for the page allocation table. */ chunk->pages = pages = size >> pageShift; res = BootAlloc(&p, boot, (size_t)BTSize(pages), MPS_PF_ALIGN); if (res != ResOK) goto failAllocTable; chunk->allocTable = p; pageTableSize = SizeAlignUp(pages * sizeof(PageUnion), chunk->pageSize); chunk->pageTablePages = pageTableSize >> pageShift; res = Method(Arena, arena, chunkInit)(chunk, boot); if (res != ResOK) goto failClassInit; /* @@@@ Is BootAllocated always right? */ /* Last thing we BootAlloc'd is pageTable. We requested pageSize */ /* alignment, and pageTableSize is itself pageSize aligned, so */ /* BootAllocated should also be pageSize aligned. */ AVER(AddrIsAligned(BootAllocated(boot), chunk->pageSize)); chunk->allocBase = (Index)(BootAllocated(boot) >> pageShift); /* Init allocTable after class init, because it might be mapped there. */ BTResRange(chunk->allocTable, 0, pages); /* Check that there is some usable address space remaining in the chunk. */ allocBase = PageIndexBase(chunk, chunk->allocBase); AVER(allocBase < chunk->limit); /* Add the chunk's free address space to the arena's freeLand, so that we can allocate from it. */ if (arena->hasFreeLand) { res = ArenaFreeLandInsert(arena, allocBase, chunk->limit); if (res != ResOK) goto failLandInsert; } TreeInit(&chunk->chunkTree); chunk->sig = ChunkSig; AVERT(Chunk, chunk); ArenaChunkInsert(arena, chunk); return ResOK; failLandInsert: Method(Arena, arena, chunkFinish)(chunk); /* .no-clean: No clean-ups needed past this point for boot, as we will discard the chunk. */ failClassInit: failAllocTable: return res; }
static NTSTATUS InitEventThread( PKQUEUE_POOL pPool, PLW_THREAD_POOL_ATTRIBUTES pAttrs, PKQUEUE_THREAD pThread, ULONG ulCpu ) { NTSTATUS status = STATUS_SUCCESS; struct kevent event; pthread_attr_t threadAttr; BOOLEAN bThreadAttrInit = FALSE; status = LwErrnoToNtStatus(pthread_attr_init(&threadAttr)); GOTO_ERROR_ON_STATUS(status); bThreadAttrInit = TRUE; pThread->pPool = pPool; status = LwErrnoToNtStatus(pthread_mutex_init(&pThread->Lock, NULL)); GOTO_ERROR_ON_STATUS(status); status = LwErrnoToNtStatus(pthread_cond_init(&pThread->Event, NULL)); GOTO_ERROR_ON_STATUS(status); if (pipe(pThread->SignalFds) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } SetCloseOnExec(pThread->SignalFds[0]); SetCloseOnExec(pThread->SignalFds[1]); if ((pThread->KqueueFd = kqueue()) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } SetCloseOnExec(pThread->KqueueFd); /* Add signal fd to kqueue set */ EV_SET(&event, pThread->SignalFds[0], EVFILT_READ, EV_ADD, 0, 0, NULL); if (kevent(pThread->KqueueFd, &event, 1, NULL, 0, NULL) < 0) { status = LwErrnoToNtStatus(errno); GOTO_ERROR_ON_STATUS(status); } RingInit(&pThread->Tasks); status = LwRtlSetAffinityThreadAttribute(&threadAttr, ulCpu); GOTO_ERROR_ON_STATUS(status); if (pAttrs && pAttrs->ulTaskThreadStackSize) { status = LwErrnoToNtStatus( pthread_attr_setstacksize(&threadAttr, pAttrs->ulTaskThreadStackSize)); GOTO_ERROR_ON_STATUS(status); } status = LwErrnoToNtStatus( pthread_create( &pThread->Thread, &threadAttr, EventThread, pThread)); GOTO_ERROR_ON_STATUS(status); error: if (bThreadAttrInit) { pthread_attr_destroy(&threadAttr); } 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; }