PageRenderTime 53ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/dna/Thread.c

https://bitbucket.org/cosi2/dotnetanywhere-wb
C | 262 lines | 184 code | 27 blank | 51 comment | 35 complexity | fd0301eed2d422b63aa572667bf60865 MD5 | raw file
  1. // Copyright (c) 2009 DotNetAnywhere
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. #include "Compat.h"
  21. #include "Sys.h"
  22. #include "Thread.h"
  23. #include "MethodState.h"
  24. #include "Heap.h"
  25. #include "Type.h"
  26. static tThread *pAllThreads = NULL;
  27. static tThread *pCurrentThread;
  28. tThread* Thread() {
  29. static U32 threadID = 0;
  30. tThread *pThis;
  31. // Create thread and initial method state. This is allocated on the managed heap, and
  32. // mark as undeletable. When the thread exits, it was marked as deletable.
  33. pThis = (tThread*)Heap_AllocType(types[TYPE_SYSTEM_THREADING_THREAD]);
  34. Heap_MakeUndeletable((HEAP_PTR)pThis);
  35. pThis->threadID = ++threadID;
  36. pThis->pCurrentMethodState = NULL;
  37. pThis->threadExitValue = 0;
  38. pThis->nextFinallyUnwindStack = 0;
  39. pThis->pAsync = NULL;
  40. pThis->hasParam = 0;
  41. pThis->startDelegate = NULL;
  42. pThis->param = NULL;
  43. pThis->state = THREADSTATE_UNSTARTED;
  44. // Allocate the first chunk of thread-local stack
  45. pThis->pThreadStack = TMALLOC(tThreadStack);
  46. pThis->pThreadStack->ofs = 0;
  47. pThis->pThreadStack->pNext = NULL;
  48. // Add to list of all thread
  49. pThis->pNextThread = pAllThreads;
  50. pAllThreads = pThis;
  51. return pThis;
  52. }
  53. void* Thread_StackAlloc(tThread *pThread, U32 size) {
  54. tThreadStack *pStack = pThread->pThreadStack;
  55. void *pAddr = pStack->memory + pStack->ofs;
  56. #if _DEBUG
  57. *(U32*)pAddr = 0xabababab;
  58. ((U32*)pAddr)++;
  59. pStack->ofs += 4;
  60. #endif
  61. pStack->ofs += size;
  62. if (pStack->ofs > THREADSTACK_CHUNK_SIZE) {
  63. Crash("Thread-local stack is too large");
  64. }
  65. #if _DEBUG
  66. memset(pAddr, 0xcd, size);
  67. *(U32*)(((char*)pAddr) + size) = 0xfbfbfbfb;
  68. pStack->ofs += 4;
  69. #endif
  70. return pAddr;
  71. }
  72. void Thread_StackFree(tThread *pThread, void *pAddr) {
  73. tThreadStack *pStack = pThread->pThreadStack;
  74. #if _DEBUG
  75. ((U32*)pAddr)--;
  76. memset(pAddr, 0xfe, pStack->ofs - (U32)(((unsigned char*)pAddr) - pStack->memory));
  77. #endif
  78. pStack->ofs = (U32)(((unsigned char*)pAddr) - pStack->memory);
  79. }
  80. void Thread_SetEntryPoint(tThread *pThis, tMetaData *pMetaData, IDX_TABLE entryPointToken, PTR params, U32 paramBytes) {
  81. // Set up the initial MethodState
  82. pThis->pCurrentMethodState = MethodState(pThis, pMetaData, entryPointToken, NULL);
  83. // Insert initial parameters (if any)
  84. if (paramBytes > 0) {
  85. memcpy(pThis->pCurrentMethodState->pParamsLocals, params, paramBytes);
  86. }
  87. }
  88. static void Thread_Delete(tThread *pThis) {
  89. tThreadStack *pStack = pThis->pThreadStack;
  90. while (pStack != NULL) {
  91. tThreadStack *pNextStack = pStack->pNext;
  92. free(pStack);
  93. pStack = pNextStack;
  94. }
  95. Heap_MakeDeletable((HEAP_PTR)pThis);
  96. }
  97. I32 Thread_Execute() {
  98. tThread *pThread, *pPrevThread;
  99. U32 status;
  100. pThread = pAllThreads;
  101. // Set the initial thread to the RUNNING state.
  102. pThread->state = THREADSTATE_RUNNING;
  103. // Set the initial CurrentThread
  104. pCurrentThread = pThread;
  105. for (;;) {
  106. U32 minSleepTime = 0xffffffff;
  107. I32 threadExitValue;
  108. status = JIT_Execute(pThread, 100);
  109. switch (status) {
  110. case THREAD_STATUS_EXIT:
  111. threadExitValue = pThread->threadExitValue;
  112. log_f(1, "Thread ID#%d exited. Return value: %d\n", (int)pThread->threadID, (int)threadExitValue);
  113. // Remove the current thread from the running threads list.
  114. // Note that this list may have changed since before the call to JIT_Execute().
  115. {
  116. tThread **ppThread = &pAllThreads;
  117. while (*ppThread != pThread) {
  118. ppThread = &((*ppThread)->pNextThread);
  119. }
  120. *ppThread = (*ppThread)->pNextThread;
  121. }
  122. // Delete the current thread
  123. Thread_Delete(pThread);
  124. // If there are no more threads left running, then exit application (by returning)
  125. // Threads that are unstarted or background do not stop the exit
  126. {
  127. tThread *pThread = pAllThreads;
  128. U32 canExit = 1;
  129. while (pThread != NULL) {
  130. if ((!(pThread->state & THREADSTATE_BACKGROUND)) && ((pThread->state & (~THREADSTATE_BACKGROUND)) != THREADSTATE_UNSTARTED)) {
  131. canExit = 0;
  132. break;
  133. }
  134. pThread = pThread->pNextThread;
  135. }
  136. if (canExit) {
  137. return threadExitValue;
  138. }
  139. }
  140. pThread = pAllThreads; // This is not really correct, but it'll work for the time being
  141. break;
  142. case THREAD_STATUS_RUNNING:
  143. case THREAD_STATUS_LOCK_EXIT:
  144. // Nothing to do
  145. break;
  146. case THREAD_STATUS_ASYNC:
  147. pThread->pAsync->startTime = msTime();
  148. break;
  149. }
  150. // Move on to the next thread.
  151. // Find the next thread that isn't sleeping or blocked on IO
  152. pPrevThread = pThread;
  153. for (;;) {
  154. pThread = pThread->pNextThread;
  155. if (pThread == NULL) {
  156. pThread = pAllThreads;
  157. }
  158. // Set the CurrentThread correctly
  159. pCurrentThread = pThread;
  160. if ((pThread->state & (~THREADSTATE_BACKGROUND)) != 0) {
  161. // Thread is not running
  162. continue;
  163. }
  164. if (pThread->pAsync != NULL) {
  165. // Discover if whatever is being waited for is finished
  166. tAsyncCall *pAsync = pThread->pAsync;
  167. if (pAsync->sleepTime >= 0) {
  168. // This is a sleep
  169. U64 nowTime = msTime();
  170. I32 msSleepRemaining = pAsync->sleepTime - (I32)(nowTime - pAsync->startTime);
  171. if (msSleepRemaining <= 0) {
  172. // Sleep is finished
  173. break;
  174. }
  175. // Sleep is not finished, so continue to next thread
  176. if ((U32)msSleepRemaining < minSleepTime) {
  177. minSleepTime = msSleepRemaining;
  178. }
  179. } else {
  180. // This is blocking IO, or a lock
  181. tMethodState *pMethodState = pThread->pCurrentMethodState;
  182. PTR pThis;
  183. U32 thisOfs;
  184. U32 unblocked;
  185. if (METHOD_ISSTATIC(pMethodState->pMethod)) {
  186. pThis = NULL;
  187. thisOfs = 0;
  188. } else {
  189. pThis = *(PTR*)pMethodState->pParamsLocals;
  190. thisOfs = 4;
  191. }
  192. unblocked = pAsync->checkFn(pThis, pMethodState->pParamsLocals + thisOfs, pMethodState->pEvalStack, pAsync);
  193. if (unblocked) {
  194. // The IO has unblocked, and the return value is ready.
  195. // So delete the async object.
  196. // TODO: The async->state object needs to be deleted somehow (maybe)
  197. free(pAsync);
  198. // And remove it from the thread
  199. pThread->pAsync = NULL;
  200. break;
  201. }
  202. minSleepTime = 5;
  203. }
  204. } else {
  205. // Thread is ready to run
  206. break;
  207. }
  208. if (pThread == pPrevThread) {
  209. // When it gets here, it means that all threads are currently blocked.
  210. //printf("All blocked; sleep(%d)\n", minSleepTime);
  211. SleepMS(minSleepTime);
  212. }
  213. }
  214. }
  215. }
  216. tThread* Thread_GetCurrent() {
  217. return pCurrentThread;
  218. }
  219. void Thread_GetHeapRoots(tHeapRoots *pHeapRoots) {
  220. tThread *pThread;
  221. pThread = pAllThreads;
  222. while (pThread != NULL) {
  223. tMethodState *pMethodState;
  224. pMethodState = pThread->pCurrentMethodState;
  225. while (pMethodState != NULL) {
  226. // Put the evaluation stack on the roots
  227. Heap_SetRoots(pHeapRoots, pMethodState->pEvalStack, pMethodState->pMethod->pJITted->maxStack);
  228. // Put the params/locals on the roots
  229. Heap_SetRoots(pHeapRoots, pMethodState->pParamsLocals,
  230. pMethodState->pMethod->parameterStackSize+pMethodState->pMethod->pJITted->localsStackSize);
  231. pMethodState = pMethodState->pCaller;
  232. }
  233. pThread = pThread->pNextThread;
  234. }
  235. }