Leaked source code of windows server 2003
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.

516 lines
17 KiB

  1. // Ruler
  2. // 1 2 3 4 5 6 7 8
  3. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  4. /********************************************************************/
  5. /* */
  6. /* The standard layout. */
  7. /* */
  8. /* The standard layout for 'cpp' files in this code is as */
  9. /* follows: */
  10. /* */
  11. /* 1. Include files. */
  12. /* 2. Constants local to the class. */
  13. /* 3. Data structures local to the class. */
  14. /* 4. Data initializations. */
  15. /* 5. Static functions. */
  16. /* 6. Class functions. */
  17. /* */
  18. /* The constructor is typically the first function, class */
  19. /* member functions appear in alphabetical order with the */
  20. /* destructor appearing at the end of the file. Any section */
  21. /* or function this is not required is simply omitted. */
  22. /* */
  23. /********************************************************************/
  24. #include "LibraryPCH.hpp"
  25. #include "Thread.hpp"
  26. /********************************************************************/
  27. /* */
  28. /* Constants local to the class. */
  29. /* */
  30. /* The thread class keeps track of active threads. */
  31. /* */
  32. /********************************************************************/
  33. CONST SBIT32 ThreadsSize = 16;
  34. /********************************************************************/
  35. /* */
  36. /* Data structures local to the class. */
  37. /* */
  38. /* When we start a thread we want to configure it. However, */
  39. /* we no longer have access to the class information. Hence, */
  40. /* we need a structure to pass over all of the interesting */
  41. /* values to the new thread. */
  42. /* */
  43. /********************************************************************/
  44. typedef struct
  45. {
  46. BOOLEAN Affinity;
  47. VOLATILE SBIT16 *Cpu;
  48. NEW_THREAD Function;
  49. SBIT16 MaxCpus;
  50. VOID *Parameter;
  51. BOOLEAN Priority;
  52. HANDLE Running;
  53. HANDLE Started;
  54. THREAD *Thread;
  55. BOOLEAN Wait;
  56. }
  57. SETUP_NEW_THREAD;
  58. /********************************************************************/
  59. /* */
  60. /* Static functions local to the class. */
  61. /* */
  62. /* The static functions used by this class are declared here. */
  63. /* */
  64. /********************************************************************/
  65. STATIC VOID CDECL NewThread( VOID *SetupParameter );
  66. /********************************************************************/
  67. /* */
  68. /* Class constructor. */
  69. /* */
  70. /* Create a thread class and initialize it. This call is not */
  71. /* thread safe and should only be made in a single thread */
  72. /* environment. */
  73. /* */
  74. /********************************************************************/
  75. THREAD::THREAD( VOID ) :
  76. //
  77. // Call the constructors for the contained classes.
  78. //
  79. Threads( ThreadsSize,NoAlignment,CacheLineSize )
  80. {
  81. //
  82. // The inital configuration.
  83. //
  84. Affinity = False;
  85. Cpu = 0;
  86. Priority = False;
  87. Stack = 0;
  88. MaxThreads = ThreadsSize;
  89. ThreadsUsed = 0;
  90. //
  91. // This event is signaled when a thread is
  92. // running.
  93. //
  94. if ( (Running = CreateEvent( NULL, FALSE, FALSE, NULL )) == NULL)
  95. { Failure( "Create event in constructor for THREAD" ); }
  96. //
  97. // This event is signaled when a new thread can
  98. // be started.
  99. //
  100. if ( (Started = CreateEvent( NULL, FALSE, TRUE, NULL )) == NULL)
  101. { Failure( "Create event in constructor for THREAD" ); }
  102. }
  103. /********************************************************************/
  104. /* */
  105. /* End a thread. */
  106. /* */
  107. /* Delete the thread handle from the internal table and then */
  108. /* terminate the thread. */
  109. /* */
  110. /********************************************************************/
  111. VOID THREAD::EndThread( VOID )
  112. {
  113. UnregisterThread();
  114. _endthread();
  115. }
  116. /********************************************************************/
  117. /* */
  118. /* Find a thread. */
  119. /* */
  120. /* Find a registered thread in the thread info table. */
  121. /* */
  122. /********************************************************************/
  123. SBIT32 THREAD::FindThread( SBIT32 ThreadId )
  124. {
  125. REGISTER SBIT32 Count;
  126. //
  127. // Find a thread in the active thread list.
  128. //
  129. for ( Count=0;Count < ThreadsUsed;Count ++ )
  130. {
  131. if ( ThreadId == Threads[ Count ].ThreadId )
  132. { return Count; }
  133. }
  134. return NoThread;
  135. }
  136. /********************************************************************/
  137. /* */
  138. /* Start a new thread. */
  139. /* */
  140. /* When a new thread is created it executes a special initial */
  141. /* function which configures it. When control returns to this */
  142. /* function the thread is terminated. */
  143. /* */
  144. /********************************************************************/
  145. STATIC VOID CDECL NewThread( VOID *SetupParameter )
  146. {
  147. AUTO SETUP_NEW_THREAD Setup = (*(SETUP_NEW_THREAD*) SetupParameter);
  148. //
  149. // Set the affinity mask to the next processor if requested.
  150. //
  151. if ( (Setup.Affinity) && (Setup.MaxCpus > 1) )
  152. {
  153. REGISTER DWORD AffinityMask;
  154. if ( (*Setup.Cpu) < Setup.MaxCpus )
  155. { AffinityMask = (1 << ((*Setup.Cpu) ++)); }
  156. else
  157. {
  158. AffinityMask = 1;
  159. (*Setup.Cpu) = 1;
  160. }
  161. if ( SetThreadAffinityMask( GetCurrentThread(),AffinityMask ) == 0 )
  162. { Failure( "Affinity mask invalid in NewThread()" ); }
  163. }
  164. //
  165. // Set the priority to 'HIGH' if requested.
  166. //
  167. if ( Setup.Priority )
  168. { SetThreadPriority( GetCurrentThread(),THREAD_PRIORITY_HIGHEST ); }
  169. //
  170. // The thread is now so add it to the table
  171. // executiong threads.
  172. //
  173. Setup.Thread -> RegisterThread();
  174. //
  175. // Wake up anyone who is waiting.
  176. //
  177. if ( Setup.Wait )
  178. { SetEvent( Setup.Running ); }
  179. SetEvent( Setup.Started );
  180. //
  181. // Call thread function.
  182. //
  183. Setup.Function( Setup.Parameter );
  184. //
  185. // The thread function has returned so exit.
  186. //
  187. Setup.Thread -> EndThread();
  188. }
  189. /********************************************************************/
  190. /* */
  191. /* Register the current thread. */
  192. /* */
  193. /* When a thread has created we can add the thread info to */
  194. /* our internal table. */
  195. /* */
  196. /********************************************************************/
  197. VOID THREAD::RegisterThread( VOID )
  198. {
  199. REGISTER SBIT32 ThreadId = GetThreadId();
  200. //
  201. // Claim a spinlock so we can update the
  202. // thread table.
  203. //
  204. Spinlock.ClaimLock();
  205. if ( FindThread( ThreadId ) == NoThread )
  206. {
  207. AUTO HANDLE NewHandle;
  208. REGISTER HANDLE Process = GetCurrentProcess();
  209. REGISTER HANDLE Thread = GetCurrentThread();
  210. //
  211. // We need to duplicate the handle so we get
  212. // a real thread handle and not the pretend
  213. // ones supplied by NT.
  214. //
  215. if
  216. (
  217. DuplicateHandle
  218. (
  219. Process,
  220. Thread,
  221. Process,
  222. & NewHandle,
  223. DUPLICATE_SAME_ACCESS,
  224. False,
  225. DUPLICATE_SAME_ACCESS
  226. )
  227. )
  228. {
  229. REGISTER THREAD_INFO *ThreadInfo;
  230. //
  231. // We may need to expand the table if there are
  232. // a large number of threads.
  233. //
  234. while ( ThreadsUsed >= MaxThreads )
  235. { Threads.Resize( (MaxThreads *= ExpandStore) ); }
  236. //
  237. // Add the thread handle to the table.
  238. //
  239. ThreadInfo = & Threads[ ThreadsUsed ++ ];
  240. ThreadInfo -> Handle = NewHandle;
  241. ThreadInfo -> ThreadId = ThreadId;
  242. }
  243. }
  244. //
  245. // We are finished so release the lock.
  246. //
  247. Spinlock.ReleaseLock();
  248. }
  249. /********************************************************************/
  250. /* */
  251. /* Set thread stack size. */
  252. /* */
  253. /* Set thread stack size. This will cause all new threads to */
  254. /* be created with the selected stack size. */
  255. /* */
  256. /********************************************************************/
  257. VOID THREAD::SetThreadStackSize( LONG Stack )
  258. {
  259. #ifdef DEBUGGING
  260. if ( Stack >= 0 )
  261. {
  262. #endif
  263. this -> Stack = Stack;
  264. #ifdef DEBUGGING
  265. }
  266. else
  267. { Failure( "Stack size in SetThreadStack()" ); }
  268. #endif
  269. }
  270. /********************************************************************/
  271. /* */
  272. /* Start a new thread. */
  273. /* */
  274. /* Start a new thread and configure it as requested by the */
  275. /* caller. If needed we will set the affinity and priority */
  276. /* of this thread later. */
  277. /* */
  278. /********************************************************************/
  279. BOOLEAN THREAD::StartThread( NEW_THREAD Function,VOID *Parameter,BOOLEAN Wait )
  280. {
  281. STATIC SETUP_NEW_THREAD Setup;
  282. //
  283. // Wait for any pending thread creations to
  284. // complete.
  285. //
  286. while
  287. (
  288. WaitForSingleObject( Started,INFINITE )
  289. !=
  290. WAIT_OBJECT_0
  291. );
  292. //
  293. // Create a thread activation record.
  294. //
  295. Setup.Affinity = Affinity;
  296. Setup.Cpu = & Cpu;
  297. Setup.Function = Function;
  298. Setup.MaxCpus = NumberOfCpus();
  299. Setup.Parameter = Parameter;
  300. Setup.Priority = Priority;
  301. Setup.Running = Running;
  302. Setup.Started = Started;
  303. Setup.Thread = this;
  304. Setup.Wait = Wait;
  305. //
  306. // Call the operating system to start the thread.
  307. //
  308. if ( _beginthread( NewThread,(unsigned) Stack,(VOID*) & Setup ) != NULL )
  309. {
  310. //
  311. // Wait for the thread to initialize is needed.
  312. //
  313. if ( Wait )
  314. {
  315. //
  316. // Wait for the thread to start to run.
  317. //
  318. while
  319. (
  320. WaitForSingleObject( Running,INFINITE )
  321. !=
  322. WAIT_OBJECT_0
  323. );
  324. }
  325. return True;
  326. }
  327. else
  328. { return False; }
  329. }
  330. /********************************************************************/
  331. /* */
  332. /* Unregister the current thread. */
  333. /* */
  334. /* When a thread has terminated we can delete the thread */
  335. /* info from our internal table. */
  336. /* */
  337. /********************************************************************/
  338. VOID THREAD::UnregisterThread( SBIT32 ThreadId )
  339. {
  340. REGISTER SBIT32 Start;
  341. //
  342. // If no 'ThreadId' assume the current thread.
  343. //
  344. if ( ThreadId == NoThread )
  345. { ThreadId = GetThreadId(); }
  346. //
  347. // Claim a spinlock so we can update the
  348. // thread table.
  349. //
  350. Spinlock.ClaimLock();
  351. //
  352. // Search for the thread info to delete
  353. // in the table.
  354. //
  355. if ( (Start = FindThread( ThreadId )) != NoThread )
  356. {
  357. REGISTER SBIT32 Count;
  358. //
  359. // Close the handle to the thread and
  360. // update the table size.
  361. //
  362. CloseHandle( Threads[ Start ].Handle );
  363. ThreadsUsed --;
  364. //
  365. // Copy down the remaining thread info.
  366. //
  367. for ( Count=Start;Count < ThreadsUsed;Count ++ )
  368. { Threads[ Count ] = Threads[ (Count+1) ]; }
  369. }
  370. //
  371. // We are finished so release the lock.
  372. //
  373. Spinlock.ReleaseLock();
  374. }
  375. /********************************************************************/
  376. /* */
  377. /* Wait for threads. */
  378. /* */
  379. /* Wait for all threads to finish and then return. As this may */
  380. /* take a while an optional timeout may be supplied. */
  381. /* */
  382. /********************************************************************/
  383. BOOLEAN THREAD::WaitForThreads( LONG WaitTime )
  384. {
  385. //
  386. // Claim a spinlock so we can read the
  387. // thread table.
  388. //
  389. Spinlock.ClaimLock();
  390. while ( ThreadsUsed > 0 )
  391. {
  392. REGISTER HANDLE Handle = (Threads[0].Handle);
  393. REGISTER SBIT32 ThreadId = (Threads[0].ThreadId);
  394. REGISTER DWORD Status;
  395. //
  396. // We are finished so release the lock.
  397. //
  398. Spinlock.ReleaseLock();
  399. //
  400. // Wait for the first thread in the thread info
  401. // table to terminate.
  402. //
  403. if
  404. (
  405. (Status = WaitForSingleObject( Handle,(DWORD) WaitTime ))
  406. ==
  407. WAIT_TIMEOUT
  408. )
  409. { return False; }
  410. //
  411. // We have woken up the thread must of terminated
  412. // or the handle is bad in some way. In any case
  413. // lets delete the handle and try to sleep again
  414. // if there are any more active threads.
  415. //
  416. UnregisterThread( ThreadId );
  417. //
  418. // Claim a spinlock so we can read the
  419. // thread table.
  420. //
  421. Spinlock.ClaimLock();
  422. }
  423. //
  424. // We are finished so release the lock.
  425. //
  426. Spinlock.ReleaseLock();
  427. return True;
  428. }
  429. /********************************************************************/
  430. /* */
  431. /* Class destructor. */
  432. /* */
  433. /* Destory the thread class. This call is not thread safe */
  434. /* and should only be made in a single thread environment. */
  435. /* */
  436. /********************************************************************/
  437. THREAD::~THREAD( VOID )
  438. {
  439. if
  440. (
  441. ! CloseHandle( Running )
  442. ||
  443. ! CloseHandle( Started )
  444. )
  445. { Failure( "Event handles in destructor for THREAD" ); }
  446. }