Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
5.7 KiB

  1. /*++
  2. Copyright (c) 2000-2001, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. threads.c
  5. Abstract:
  6. This file contains functions that support our threading efforts
  7. Functions found in this file:
  8. GetThreadInfoSafe
  9. UninitThread
  10. Revision History:
  11. 01 Mar 2001 v-michka Created.
  12. --*/
  13. #include "precomp.h"
  14. //
  15. // The MEM structure. We store a linked list of these. In our
  16. // most optimal case, this is a list with just one MEM in it.
  17. //
  18. struct MEM
  19. {
  20. LPGODOTTLSINFO alloc; // the allocation to store
  21. struct MEM* next; // Pointer to the next MEM to chain to
  22. };
  23. struct MEM* m_memHead;
  24. /*-------------------------------
  25. GetThreadInfoSafe
  26. Returns our TLS info, and if it has never been gotten,
  27. allocates it (if the caller specifies) and returns the
  28. newly allocated info.
  29. -------------------------------*/
  30. LPGODOTTLSINFO GetThreadInfoSafe(BOOL fAllocate)
  31. {
  32. LPGODOTTLSINFO lpgti = NULL;
  33. DWORD dwLastError = ERROR_SUCCESS;
  34. // Use SEH around our critical section since low memory
  35. // situations can cause a STATUS_INVALID_HANDLE exception
  36. // to be raise. We will simply set the last error for this
  37. // case so the client can always know why we failed
  38. // CONSIDER: Use ERROR_LOCK_FAILED or ERROR_LOCKED here?
  39. __try
  40. {
  41. EnterCriticalSection(&g_csThreads);
  42. lpgti = TlsGetValue(g_tls);
  43. dwLastError = GetLastError();
  44. if(!lpgti)
  45. {
  46. if(fAllocate)
  47. {
  48. struct MEM* newThreadMem;
  49. lpgti = GodotHeapAlloc(sizeof(GODOTTLSINFO));
  50. if(!lpgti)
  51. dwLastError = ERROR_OUTOFMEMORY;
  52. else
  53. {
  54. // First lets add the block to our
  55. // handy linked list of allocations.
  56. if(newThreadMem = GodotHeapAlloc(sizeof(struct MEM)))
  57. {
  58. newThreadMem->alloc = lpgti;
  59. newThreadMem->next = m_memHead;
  60. m_memHead = newThreadMem;
  61. // Now lets store it in the TLS slot.
  62. dwLastError = GetLastError();
  63. TlsSetValue(g_tls, lpgti);
  64. }
  65. else
  66. dwLastError = ERROR_OUTOFMEMORY;
  67. if(dwLastError != ERROR_SUCCESS)
  68. {
  69. // we failed somehow, so clean it all up
  70. GodotHeapFree(lpgti);
  71. m_memHead = m_memHead->next;
  72. GodotHeapFree(newThreadMem);
  73. lpgti = NULL;
  74. }
  75. }
  76. }
  77. else
  78. dwLastError=ERROR_OUTOFMEMORY;
  79. }
  80. }
  81. __finally
  82. {
  83. LeaveCriticalSection(&g_csThreads);
  84. }
  85. if(lpgti == NULL)
  86. {
  87. SetLastError(dwLastError);
  88. return(NULL);
  89. }
  90. return(lpgti);
  91. }
  92. /*-------------------------------
  93. UninitThread
  94. -------------------------------*/
  95. void UninitThread(void)
  96. {
  97. LPGODOTTLSINFO lpgti;
  98. if(g_tls)
  99. {
  100. // don't alloc if its not there!
  101. lpgti = GetThreadInfoSafe(FALSE);
  102. // Use SEH around our critical section since low memory
  103. // situations can cause a STATUS_INVALID_HANDLE exception
  104. // to be raise. Note that if we fail to enter our CS that
  105. // missing out on this alloc is the least of our problems.
  106. // We will get a second chance at process close to free
  107. // it up, if we ever get there.
  108. __try
  109. {
  110. EnterCriticalSection(&g_csThreads);
  111. if(lpgti)
  112. {
  113. struct MEM* current = m_memHead;
  114. // Clean up that ol' heap allocated memory
  115. GodotHeapFree(lpgti);
  116. while(current != NULL)
  117. {
  118. if(current->alloc == lpgti)
  119. {
  120. // Must handle the head case separately
  121. m_memHead = current->next;
  122. current->alloc = NULL;
  123. GodotHeapFree(current);
  124. break;
  125. }
  126. if((current->next != NULL) && (current->next->alloc == lpgti))
  127. {
  128. // The next one in line is the
  129. // one we want to free up
  130. current->next = current->next->next;
  131. current->next->alloc = NULL;
  132. GodotHeapFree(current->next);
  133. break;
  134. }
  135. current = current->next;
  136. }
  137. TlsSetValue(g_tls, NULL);
  138. }
  139. }
  140. __finally
  141. {
  142. LeaveCriticalSection(&g_csThreads);
  143. }
  144. }
  145. return;
  146. }
  147. /*-------------------------------
  148. UninitAllThreads
  149. Deletes our entire linked list of allocations. Note that we
  150. can only call TlsSetValue on the current thread, not others.
  151. However, this function will invalidate any pointers in other
  152. threads so this function should NEVER be called until process
  153. close.
  154. -------------------------------*/
  155. void UninitAllThreads(void)
  156. {
  157. struct MEM* current;
  158. struct MEM* next;
  159. __try
  160. {
  161. EnterCriticalSection(&g_csThreads);
  162. current = m_memHead;
  163. while (current != NULL)
  164. {
  165. next = current->next;
  166. GodotHeapFree(current->alloc);
  167. GodotHeapFree(current);
  168. current = next;
  169. }
  170. m_memHead = NULL;
  171. }
  172. __finally
  173. {
  174. LeaveCriticalSection(&g_csThreads);
  175. }
  176. }