public static void StackFree(tThread *pThread, void *pAddr) { tThreadStack *pStack = pThread->pThreadStack; #if _DEBUG ((uint *)pAddr)--; Mem.memset(pAddr, 0xfe, pStack->ofs - (uint)(((byte *)pAddr) - pStack->memory)); #endif pStack->ofs = (uint)(((byte *)pAddr) - pStack->memory); }
static void Delete(tThread *pThis) { tThreadStack *pStack = pThis->pThreadStack; while (pStack != null) { tThreadStack *pNextStack = pStack->pNext; Mem.free(pStack); pStack = pNextStack; } Heap.MakeDeletable((/*HEAP_PTR*/ byte *)pThis); }
public static tMethodState *Direct(tThread *pThread, tMD_MethodDef *pMethod, tMethodState *pCaller, uint isInternalNewObjCall) { tMethodState *pThis; Mem.heapcheck(); if (pMethod->isFilled == 0) { tMD_TypeDef *pTypeDef; pTypeDef = MetaData.GetTypeDefFromMethodDef(pMethod); MetaData.Fill_TypeDef(pTypeDef, null, null); } pThis = (tMethodState *)Thread.StackAlloc(pThread, (uint)sizeof(tMethodState)); pThis->finalizerThis = null; pThis->pCaller = pCaller; pThis->pMetaData = pMethod->pMetaData; pThis->pMethod = pMethod; if (pMethod->pJITted == null) { // If method has not already been JITted JIT.Prepare(pMethod, 0); } pThis->pJIT = pMethod->pJITted; pThis->ipOffset = 0; pThis->pEvalStack = (byte *)Thread.StackAlloc(pThread, pThis->pMethod->pJITted->maxStack); pThis->stackOfs = 0; pThis->isInternalNewObjCall = isInternalNewObjCall; pThis->pNextDelegate = null; pThis->pDelegateParams = null; pThis->pParamsLocals = (byte *)Thread.StackAlloc(pThread, pMethod->parameterStackSize + pMethod->pJITted->localsStackSize); Mem.memset(pThis->pParamsLocals, 0, pMethod->parameterStackSize + pMethod->pJITted->localsStackSize); #if DIAG_METHOD_CALLS // Keep track of the number of times this method is called pMethod->callCount++; pThis->startTime = microTime(); #endif Mem.heapcheck(); return(pThis); }
public static tThread *New() { tThread *pThis; // Create thread and initial method state. This is allocated on the managed heap, and // mark as undeletable. When the thread exits, it was marked as deletable. pThis = (tThread *)Heap.AllocType(Type.types[Type.TYPE_SYSTEM_THREADING_THREAD]); Heap.MakeUndeletable((/*HEAP_PTR*/ byte *)pThis); Mem.memset(pThis, 0, (SIZE_T)sizeof(tThread)); pThis->threadID = ++threadID; Reset(pThis); // Add to list of all thread pThis->pNextThread = pAllThreads; pAllThreads = pThis; return(pThis); }
// Returns 1 if all is OK // Returns 0 if the wrong thread is releasing the sync, or if no thread hold the sync public static uint SyncExit(/*HEAP_PTR*/ byte *obj) { tHeapEntry *pHeapEntry = GET_HEAPENTRY(obj); tThread * pThread = Thread.GetCurrent(); if (pHeapEntry->pSync == null) { return(0); } if (pHeapEntry->pSync->pThread != pThread) { return(0); } if (--pHeapEntry->pSync->count == 0) { DeleteSync(pHeapEntry); } return(1); }
static void Reset(tThread *pThis) { pThis->pCurrentMethodState = null; pThis->threadExitValue = 0; pThis->nextFinallyUnwindStack = 0; pThis->pAsync = null; pThis->hasParam = 0; pThis->startDelegate = null; pThis->param = null; pThis->state = THREADSTATE_UNSTARTED; // Allocate the first chunk of thread-local stack if (pThis->pThreadStack == null) { pThis->pThreadStack = ((tThreadStack *)Mem.malloc((SIZE_T)sizeof(tThreadStack))); pThis->pThreadStack->pNext = null; } pThis->pThreadStack->ofs = 0; }
// Return 1 if lock succesfully got // Return 0 if couldn't get the lock this time public static uint SyncTryEnter(/*HEAP_PTR*/ byte *obj) { tHeapEntry *pHeapEntry = GET_HEAPENTRY(obj); tThread * pThread = Thread.GetCurrent(); tSync * pSync; pSync = EnsureSync(pHeapEntry); if (pSync->pThread == null) { pSync->pThread = pThread; pSync->count = 1; return(1); } if (pSync->pThread == pThread) { pSync->count++; return(1); } return(0); }
public static void *StackAlloc(tThread *pThread, uint size) { tThreadStack *pStack = pThread->pThreadStack; void * pAddr = pStack->memory + pStack->ofs; #if _DEBUG *(uint *)pAddr = 0xabababab; ((uint *)pAddr)++; pStack->ofs += 4; #endif pStack->ofs += size; if (pStack->ofs > tThreadStack.THREADSTACK_CHUNK_SIZE) { Sys.Crash("Thread-local stack is too large"); } #if _DEBUG Mem.memset(pAddr, 0xcd, size); *(uint *)(((byte *)pAddr) + size) = 0xfbfbfbfb; pStack->ofs += 4; #endif return(pAddr); }
public static uint Update(uint maxInstr, int *pReturnCode) { tThread *pThread; tThread *pPrevThread; uint status; pThread = pAllThreads; // Set the initial thread to the RUNNING state. pThread->state = THREADSTATE_RUNNING; // Set the initial CurrentThread pCurrentThread = pThread; for (;;) { uint minSleepTime = 0xffffffff; int threadExitValue; status = JIT_Execute.Execute(pThread, maxInstr); switch (status) { case Thread.THREAD_STATUS_EXIT: threadExitValue = pThread->threadExitValue; Sys.log_f(1, "Thread ID#%d exited. Return value: %d\n", (int)pThread->threadID, (int)threadExitValue); // Remove the current thread from the running threads list. // Note that this list may have changed since before the call to JitOps.JIT_Execute(). { if (pAllThreads == pThread) { pAllThreads = pAllThreads->pNextThread; } else { tThread *pThread1 = pAllThreads; while (pThread1->pNextThread != pThread) { pThread1 = pThread1->pNextThread; } pThread1->pNextThread = pThread1->pNextThread->pNextThread; } } // Delete the current thread Thread.Delete(pThread); // If there are no more threads left running, then exit application (by returning) // Threads that are unstarted or background do not stop the exit // [Steve edit] Threads that are suspended also do not stop the exit. This is because you'd just // wait forever for them if they did. Note that 'exit' doesn't mean tearing down the process // like in a regular .NET runtime case. The application state is still there and we can make // further calls into it to create new threads. { tThread *pThread2 = pAllThreads; uint canExit = 1; while (pThread2 != null) { if ( ((pThread2->state & THREADSTATE_BACKGROUND) == 0) && ((pThread2->state & (~THREADSTATE_BACKGROUND)) != THREADSTATE_UNSTARTED) && ((pThread2->state & (~THREADSTATE_BACKGROUND)) != THREADSTATE_SUSPENDED)) { canExit = 0; break; } pThread2 = pThread2->pNextThread; } if (canExit != 0) { if (pReturnCode != null) { *pReturnCode = threadExitValue; } return(THREADSTATE_STOPPED); } } pThread = pAllThreads; // This is not really correct, but it'll work for the time being break; case THREAD_STATUS_RUNNING: case THREAD_STATUS_LOCK_EXIT: // Nothing to do break; case THREAD_STATUS_ASYNC: pThread->pAsync->startTime = Sys.msTime(); break; } // Move on to the next thread. // Find the next thread that isn't sleeping or blocked on IO pPrevThread = pThread; for (;;) { pThread = pThread->pNextThread; if (pThread == null) { // That was the thread -- return! return(THREADSTATE_RUNNING); } // Set the CurrentThread correctly pCurrentThread = pThread; if ((pThread->state & (~THREADSTATE_BACKGROUND)) != 0) { // Thread is not running continue; } if (pThread->pAsync != null) { // Discover if whatever is being waited for is finished tAsyncCall *pAsync = pThread->pAsync; if (pAsync->sleepTime >= 0) { // This is a sleep ulong nowTime = Sys.msTime(); int msSleepRemaining = pAsync->sleepTime - (int)(nowTime - pAsync->startTime); if (msSleepRemaining <= 0) { // Sleep is finished break; } // Sleep is not finished, so continue to next thread if ((uint)msSleepRemaining < minSleepTime) { minSleepTime = (uint)msSleepRemaining; } } else { // This is blocking IO, or a lock tMethodState *pMethodState = pThread->pCurrentMethodState; byte * pThis; uint thisOfs; uint unblocked; if (MetaData.METHOD_ISSTATIC(pMethodState->pMethod)) { pThis = null; thisOfs = 0; } else { pThis = *(byte **)pMethodState->pParamsLocals; thisOfs = 4; } unblocked = ((fnInternalCallCheck)H.ToObj(pAsync->checkFn))(null, pThis, pMethodState->pParamsLocals + thisOfs, pMethodState->pEvalStack, pAsync); if (unblocked != 0) { // The IO has unblocked, and the return value is ready. // So delete the async object. // TODO: The async->state object needs to be deleted somehow (maybe) Mem.free(pAsync); // And remove it from the thread pThread->pAsync = null; break; } minSleepTime = 5; } } else { // Thread is ready to run break; } if (pThread == pPrevThread) { // When it gets here, it means that all threads are currently blocked. //printf("All blocked; sleep(%d)\n", minSleepTime); Sys.SleepMS(minSleepTime); } } } }