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.

437 lines
14 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: Thread.cpp
  3. //
  4. // Copyright (c) 1999-2000, Microsoft Corporation
  5. //
  6. // Base class that implements thread functionality. Subclass this class and
  7. // implement the virtual ThreadEntry function. When you instantiate this
  8. // class a thread gets created which will call ThreadEntry and when that
  9. // function exits will call ThreadExit. These objects should be created using
  10. // operator new because the default implementation of ThreadExit does
  11. // "delete this". You should override this function if you don't want this
  12. // behavior. The threads are also created SUSPENDED. You make any changes
  13. // that are required in the subclass' constructor. At the end of the
  14. // constructor or from the caller of operator new a "->Resume()" can be
  15. // invoked to start the thread.
  16. //
  17. // History: 1999-08-24 vtan created
  18. // 2000-02-01 vtan moved from Neptune to Whistler
  19. // --------------------------------------------------------------------------
  20. #include "StandardHeader.h"
  21. #include "Thread.h"
  22. #include "Access.h"
  23. #include "Impersonation.h"
  24. #include "StatusCode.h"
  25. #include "TokenInformation.h"
  26. // --------------------------------------------------------------------------
  27. // CThread::CThread
  28. //
  29. // Arguments: stackSpace = Size of stack to reserve for this
  30. // thread. Default = system default.
  31. // createFlags = Additional flags designating how
  32. // the thread should be created.
  33. // Default = none.
  34. // hToken = User token to assign to the
  35. // thread. Default = none.
  36. // pSecurityDescriptor = SecurityDescriptor to assign to
  37. // thread. Default = none.
  38. //
  39. // Returns: <none>
  40. //
  41. // Purpose: Initializes the CThread object. Creates the thread SUSPENDED
  42. // with given security attributes and assigns the hToken to the
  43. // thread. The token need not have SecurityImpersonation as a
  44. // duplicate is made with this access mode.
  45. //
  46. // History: 1999-08-24 vtan created
  47. // 2000-02-01 vtan moved from Neptune to Whistler
  48. // --------------------------------------------------------------------------
  49. CThread::CThread (DWORD stackSpace, DWORD createFlags, HANDLE hToken) :
  50. CCountedObject(),
  51. _hThread(NULL),
  52. _fCompleted(false)
  53. {
  54. DWORD dwThreadID;
  55. // It is important to create the thread suspended. This constructor could
  56. // get pre-empted by the system and does. If pre-empted whilst executing
  57. // the constructor, the derived class is NOT fully constructed and the
  58. // virtual table isn't correctly initialized.
  59. _hThread = CreateThread(NULL,
  60. stackSpace,
  61. ThreadEntryProc,
  62. this,
  63. createFlags | CREATE_SUSPENDED,
  64. &dwThreadID);
  65. if (_hThread != NULL)
  66. {
  67. // Make a call to CCountedObject::AddRef here. This reference belongs
  68. // to the thread. It's necessary to do it now because the creator of
  69. // this thread can release its reference before the thread even begins
  70. // executing which would cause the object to be released!
  71. // CThread::ThreadEntryProc will release this reference when the
  72. // thread's execution is finished. The creator of this thread should
  73. // release its reference when it's done with the thread which may be
  74. // immediately in the case of an asynhronous operation in which the
  75. // thread cleans itself up.
  76. AddRef();
  77. // Impersonate the user token if given. Also grant access to the thread
  78. // object to the user. This will allow them to query thread information.
  79. if (hToken != NULL)
  80. {
  81. TSTATUS(SetToken(hToken));
  82. }
  83. }
  84. }
  85. // --------------------------------------------------------------------------
  86. // CThread::~CThread
  87. //
  88. // Arguments: <none>
  89. //
  90. // Returns: <none>
  91. //
  92. // Purpose: Releases resources used by the CThread object on thread
  93. // termination.
  94. //
  95. // History: 1999-08-24 vtan created
  96. // --------------------------------------------------------------------------
  97. CThread::~CThread (void)
  98. {
  99. ASSERTMSG(_fCompleted, "CThread::~CThread called before ThreadEntry() completed");
  100. ReleaseHandle(_hThread);
  101. }
  102. // --------------------------------------------------------------------------
  103. // CThread::operator HANDLE
  104. //
  105. // Arguments: <none>
  106. //
  107. // Returns: <none>
  108. //
  109. // Purpose: Magically converts a CThread to a HANDLE
  110. //
  111. // History: 1999-09-21 vtan created
  112. // --------------------------------------------------------------------------
  113. CThread::operator HANDLE (void) const
  114. {
  115. return(_hThread);
  116. }
  117. // --------------------------------------------------------------------------
  118. // CThread::IsCreated
  119. //
  120. // Arguments: <none>
  121. //
  122. // Returns: bool
  123. //
  124. // Purpose: Returns whether a thread was created or not.
  125. //
  126. // History: 2000-09-08 vtan created
  127. // --------------------------------------------------------------------------
  128. bool CThread::IsCreated (void) const
  129. {
  130. return(_hThread != NULL);
  131. }
  132. // --------------------------------------------------------------------------
  133. // CThread::Suspend
  134. //
  135. // Arguments: <none>
  136. //
  137. // Returns: <none>
  138. //
  139. // Purpose: Suspends thread execution.
  140. //
  141. // History: 1999-08-24 vtan created
  142. // --------------------------------------------------------------------------
  143. void CThread::Suspend (void) const
  144. {
  145. if (SuspendThread(_hThread) == 0xFFFFFFFF)
  146. {
  147. DISPLAYMSG("SuspendThread failed for thread handle in CThread::Suspend");
  148. }
  149. }
  150. // --------------------------------------------------------------------------
  151. // CThread::Resume
  152. //
  153. // Arguments: <none>
  154. //
  155. // Returns: <none>
  156. //
  157. // Purpose: Resumes thread execution.
  158. //
  159. // History: 1999-08-24 vtan created
  160. // --------------------------------------------------------------------------
  161. void CThread::Resume (void) const
  162. {
  163. if ((_hThread == NULL) || (ResumeThread(_hThread) == 0xFFFFFFFF))
  164. {
  165. DISPLAYMSG("ResumeThread failed for thread handle in CThread::Resume");
  166. }
  167. }
  168. // --------------------------------------------------------------------------
  169. // CThread::Terminate
  170. //
  171. // Arguments: <none>
  172. //
  173. // Returns: NTSTATUS
  174. //
  175. // Purpose: Forcibly terminates the thread. Use this with care. It should
  176. // only be used in case a sub-class constructor fails and the
  177. // thread is suspended and hasn't even run yet.
  178. //
  179. // History: 2000-10-18 vtan created
  180. // --------------------------------------------------------------------------
  181. NTSTATUS CThread::Terminate (void)
  182. {
  183. NTSTATUS status;
  184. if (TerminateThread(_hThread, 0) != FALSE)
  185. {
  186. _fCompleted = true;
  187. Release();
  188. ReleaseHandle(_hThread);
  189. status = STATUS_SUCCESS;
  190. }
  191. else
  192. {
  193. status = CStatusCode::StatusCodeOfLastError();
  194. }
  195. return(status);
  196. }
  197. // --------------------------------------------------------------------------
  198. // CThread::IsCompleted
  199. //
  200. // Arguments: <none>
  201. //
  202. // Returns: bool
  203. //
  204. // Purpose: Determines whether the thread has completed execution. This
  205. // does not check the signaled state of the thread handle but
  206. // rather checks member variables.
  207. //
  208. // History: 1999-08-24 vtan created
  209. // --------------------------------------------------------------------------
  210. bool CThread::IsCompleted (void) const
  211. {
  212. DWORD dwExitCode;
  213. return((GetExitCodeThread(_hThread, &dwExitCode) != FALSE) && (dwExitCode != STILL_ACTIVE));
  214. }
  215. // --------------------------------------------------------------------------
  216. // CThread::WaitForCompletion
  217. //
  218. // Arguments: dwMilliseconds = Number of milliseconds to wait for
  219. // thread completion.
  220. //
  221. // Returns: DWORD
  222. //
  223. // Purpose: Waits for the thread handle to become signaled.
  224. //
  225. // History: 1999-08-24 vtan created
  226. // --------------------------------------------------------------------------
  227. DWORD CThread::WaitForCompletion (DWORD dwMilliseconds) const
  228. {
  229. DWORD dwWaitResult;
  230. do
  231. {
  232. // When waiting for the object check to see that it's not signaled.
  233. // If signaled then abandon the wait loop. Otherwise allow user32
  234. // to continue processing messages for this thread.
  235. dwWaitResult = WaitForSingleObject(_hThread, 0);
  236. if (dwWaitResult != WAIT_OBJECT_0)
  237. {
  238. dwWaitResult = MsgWaitForMultipleObjects(1, &_hThread, FALSE, dwMilliseconds, QS_ALLINPUT);
  239. if (dwWaitResult == WAIT_OBJECT_0 + 1)
  240. {
  241. MSG msg;
  242. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE)
  243. {
  244. (BOOL)TranslateMessage(&msg);
  245. (LRESULT)DispatchMessage(&msg);
  246. }
  247. }
  248. }
  249. } while (dwWaitResult == WAIT_OBJECT_0 + 1);
  250. return(dwWaitResult);
  251. }
  252. // --------------------------------------------------------------------------
  253. // CThread::GetResult
  254. //
  255. // Arguments: <none>
  256. //
  257. // Returns: DWORD
  258. //
  259. // Purpose: Gets the thread's exit code. This assumes it has completed
  260. // execution and returns STILL_ACTIVE if not completed.
  261. //
  262. // History: 1999-08-24 vtan created
  263. // --------------------------------------------------------------------------
  264. DWORD CThread::GetResult (void) const
  265. {
  266. DWORD dwResult;
  267. if (GetExitCodeThread(_hThread, &dwResult) == FALSE)
  268. {
  269. dwResult = STILL_ACTIVE;
  270. }
  271. return(dwResult);
  272. }
  273. // --------------------------------------------------------------------------
  274. // CThread::GetPriority
  275. //
  276. // Arguments: <none>
  277. //
  278. // Returns: int
  279. //
  280. // Purpose: Gets the thread's priority.
  281. //
  282. // History: 1999-08-24 vtan created
  283. // --------------------------------------------------------------------------
  284. int CThread::GetPriority (void) const
  285. {
  286. return(GetThreadPriority(_hThread));
  287. }
  288. // --------------------------------------------------------------------------
  289. // CThread::SetPriority
  290. //
  291. // Arguments: newPriority = New priority for the thread.
  292. //
  293. // Returns: <none>
  294. //
  295. // Purpose: Sets the thread's priority.
  296. //
  297. // History: 1999-08-24 vtan created
  298. // --------------------------------------------------------------------------
  299. void CThread::SetPriority (int newPriority) const
  300. {
  301. if (SetThreadPriority(_hThread, newPriority) == 0)
  302. {
  303. DISPLAYMSG("SetThreadPriorty failed in CThread::SetPriority");
  304. }
  305. }
  306. // --------------------------------------------------------------------------
  307. // CThread::ThreadExit
  308. //
  309. // Arguments: <none>
  310. //
  311. // Returns: <none>
  312. //
  313. // Purpose: Default base class implementation of thread exit. For threads
  314. // whose execution is self contained and termination is not an
  315. // issue then this will clean up after the thread. This function
  316. // should be overriden if this behavior is NOT desired.
  317. //
  318. // History: 1999-08-24 vtan created
  319. // --------------------------------------------------------------------------
  320. void CThread::Exit (void)
  321. {
  322. }
  323. // --------------------------------------------------------------------------
  324. // CThread::SetToken
  325. //
  326. // Arguments: hToken = HANDLE to the user token to assign to this thread.
  327. //
  328. // Returns: NTSTATUS
  329. //
  330. // Purpose: Sets the impersonation token associated with this thread so
  331. // the thread will execute in the user's context from the start.
  332. //
  333. // History: 1999-09-23 vtan created
  334. // --------------------------------------------------------------------------
  335. NTSTATUS CThread::SetToken (HANDLE hToken)
  336. {
  337. PSID pLogonSID;
  338. CTokenInformation tokenInformation(hToken);
  339. pLogonSID = tokenInformation.GetLogonSID();
  340. if (pLogonSID != NULL)
  341. {
  342. CSecuredObject threadSecurity(_hThread, SE_KERNEL_OBJECT);
  343. TSTATUS(threadSecurity.Allow(pLogonSID,
  344. THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
  345. 0));
  346. TSTATUS(CImpersonation::ImpersonateUser(_hThread, hToken));
  347. }
  348. return(STATUS_SUCCESS);
  349. }
  350. // --------------------------------------------------------------------------
  351. // CThread::ThreadEntryProc
  352. //
  353. // Arguments: pParameter = "this" object.
  354. //
  355. // Returns: DWORD
  356. //
  357. // Purpose: Entry procedure for the thread. This manages the type-casting
  358. // and invokation of CThread::ThreadEntry and CThread::ThreadExit
  359. // as well as the _fCompleted member variable.
  360. //
  361. // History: 1999-08-24 vtan created
  362. // --------------------------------------------------------------------------
  363. DWORD WINAPI CThread::ThreadEntryProc (void *parameter)
  364. {
  365. DWORD dwThreadResult;
  366. CThread *pThread;
  367. pThread = static_cast<CThread*>(parameter);
  368. dwThreadResult = pThread->Entry();
  369. pThread->_fCompleted = true;
  370. pThread->Exit();
  371. pThread->Release();
  372. return(dwThreadResult);
  373. }