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.

472 lines
16 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. /* Static functions local to the class. */
  37. /* */
  38. /* The static functions used by this class are declared here. */
  39. /* */
  40. /********************************************************************/
  41. STATIC VOID CDECL MonitorThread( VOID *Parameter );
  42. STATIC VOID CDECL NewThread( VOID *Parameter );
  43. /********************************************************************/
  44. /* */
  45. /* Class constructor. */
  46. /* */
  47. /* Create a thread class and initialize it. This call is not */
  48. /* thread safe and should only be made in a single thread */
  49. /* environment. */
  50. /* */
  51. /********************************************************************/
  52. THREAD::THREAD( VOID ) :
  53. //
  54. // Call the constructors for the contained classes.
  55. //
  56. Threads( ThreadsSize,NoAlignment,CacheLineSize )
  57. {
  58. //
  59. // Setup the initial flags.
  60. //
  61. Active = True;
  62. //
  63. // The inital configuration.
  64. //
  65. ActiveThreads = 0;
  66. MaxThreads = ThreadsSize;
  67. Affinity = False;
  68. Cpu = 0;
  69. Priority = False;
  70. Stack = 0;
  71. //
  72. // This event is signaled when all threads are
  73. // complete.
  74. //
  75. if ( (Completed = CreateEvent( NULL, FALSE, FALSE, NULL )) == NULL)
  76. { Failure( "Create event in constructor for THREAD" ); }
  77. //
  78. // This event is signaled when a thread is
  79. // running.
  80. //
  81. if ( (Running = CreateEvent( NULL, FALSE, FALSE, NULL )) == NULL)
  82. { Failure( "Create event in constructor for THREAD" ); }
  83. //
  84. // This event is signaled when a new thread can
  85. // be started.
  86. //
  87. if ( (Started = CreateEvent( NULL, FALSE, TRUE, NULL )) == NULL)
  88. { Failure( "Create event in constructor for THREAD" ); }
  89. //
  90. // A thread is started whos job in life is to monitor
  91. // all the other threads.
  92. //
  93. if ( _beginthread( MonitorThread,0,((VOID*) this) ) == NULL )
  94. { Failure( "Monitor thread in constructor for THREAD" ); }
  95. }
  96. /********************************************************************/
  97. /* */
  98. /* End a thread. */
  99. /* */
  100. /* Terminate the current thread. */
  101. /* */
  102. /********************************************************************/
  103. VOID THREAD::EndThread( VOID )
  104. { _endthread(); }
  105. /********************************************************************/
  106. /* */
  107. /* The monitor thread. */
  108. /* */
  109. /* The monitor thread simply watches the lifetimes of all the */
  110. /* other threads in the process. */
  111. /* */
  112. /********************************************************************/
  113. STATIC VOID CDECL MonitorThread( VOID *Parameter )
  114. {
  115. AUTO SBIT32 Current = 0;
  116. REGISTER THREAD *Thread = ((THREAD*) Parameter);
  117. //
  118. // The monitor thread only remains active while
  119. // the class is active.
  120. //
  121. while ( Thread -> Active )
  122. {
  123. //
  124. // There is little point in trying to sleep
  125. // on a thread handle if no threads are active.
  126. //
  127. if ( Thread -> ActiveThreads > 0 )
  128. {
  129. REGISTER DWORD Status =
  130. (WaitForSingleObject( Thread -> Threads[ Current ],1 ));
  131. //
  132. // Claim a spinlock so we can update the
  133. // thread table.
  134. //
  135. Thread -> Spinlock.ClaimLock();
  136. //
  137. // A wait can terminate in various ways
  138. // each of which is dealt with here.
  139. //
  140. switch ( Status )
  141. {
  142. case WAIT_OBJECT_0:
  143. {
  144. REGISTER SBIT32 *ActiveThreads = & Thread -> ActiveThreads;
  145. //
  146. // The thread has terminated so close
  147. // the thread handle.
  148. //
  149. CloseHandle( Thread -> Threads[ Current ] );
  150. //
  151. // Delete the handle from the table
  152. // if it was not the last entry.
  153. //
  154. if ( (-- (*ActiveThreads)) > 0 )
  155. {
  156. REGISTER SBIT32 Count;
  157. //
  158. // Copy down the remaining
  159. // thread handles.
  160. //
  161. for ( Count=Current;Count < (*ActiveThreads);Count ++ )
  162. {
  163. Thread -> Threads[ Count ] =
  164. Thread -> Threads[ (Count+1) ];
  165. }
  166. //
  167. // We may need to wrap around to
  168. // the start of the array.
  169. //
  170. Current %= (*ActiveThreads);
  171. }
  172. else
  173. { SetEvent( Thread -> Completed ); }
  174. break;
  175. }
  176. case WAIT_TIMEOUT:
  177. {
  178. //
  179. // The thread is still active so try the
  180. // next thread handle.
  181. //
  182. Current = ((Current + 1) % Thread -> ActiveThreads);
  183. break;
  184. }
  185. case WAIT_FAILED:
  186. { Failure( "Wait fails in MonitorThread" ); }
  187. default:
  188. { Failure( "Missing case in MonitorThread" ); }
  189. }
  190. //
  191. // We are finished so release the lock.
  192. //
  193. Thread -> Spinlock.ReleaseLock();
  194. }
  195. else
  196. { Sleep( 1 ); }
  197. }
  198. }
  199. /********************************************************************/
  200. /* */
  201. /* Start a new thread. */
  202. /* */
  203. /* When a new thread is created it executes a special initial */
  204. /* function which configures it. When control returns to this */
  205. /* function the thread is terminated. */
  206. /* */
  207. /********************************************************************/
  208. STATIC VOID CDECL NewThread( VOID *Parameter )
  209. {
  210. REGISTER THREAD *Thread = ((THREAD*) Parameter);
  211. REGISTER NEW_THREAD ThreadFunction = Thread -> ThreadFunction;
  212. REGISTER VOID *ThreadParameter = Thread -> ThreadParameter;
  213. //
  214. // Set the affinity mask to the next processor
  215. // if requested.
  216. //
  217. if ( (Thread -> Affinity) && (Thread -> NumberOfCpus() > 1) )
  218. {
  219. REGISTER DWORD AffinityMask;
  220. if ( (Thread -> Cpu) < (Thread -> NumberOfCpus()) )
  221. { AffinityMask = (1 << (Thread -> Cpu ++)); }
  222. else
  223. {
  224. AffinityMask = 1;
  225. Thread -> Cpu = 1;
  226. }
  227. if ( SetThreadAffinityMask( GetCurrentThread(),AffinityMask ) == 0 )
  228. { Failure( "Affinity mask invalid in NewThread()" ); }
  229. }
  230. //
  231. // Set the priority to 'HIGH' if requested.
  232. //
  233. if ( Thread -> Priority )
  234. { SetThreadPriority( GetCurrentThread(),THREAD_PRIORITY_HIGHEST ); }
  235. //
  236. // The thread is now ready so add it to the table
  237. // executiong threads.
  238. //
  239. Thread -> RegisterThread();
  240. //
  241. // Wake up anyone who is waiting.
  242. //
  243. if ( Thread -> ThreadWait )
  244. { SetEvent( Thread -> Running ); }
  245. SetEvent( Thread -> Started );
  246. //
  247. // Call the thread function.
  248. //
  249. ThreadFunction( ThreadParameter );
  250. //
  251. // The thread function has returned so exit.
  252. //
  253. Thread -> EndThread();
  254. }
  255. /********************************************************************/
  256. /* */
  257. /* Register the current thread. */
  258. /* */
  259. /* When a thread has created we can add the thread info to */
  260. /* our internal table. */
  261. /* */
  262. /********************************************************************/
  263. VOID THREAD::RegisterThread( VOID )
  264. {
  265. AUTO HANDLE NewHandle;
  266. REGISTER HANDLE Process = GetCurrentProcess();
  267. REGISTER HANDLE Thread = GetCurrentThread();
  268. //
  269. // Claim a spinlock so we can update the
  270. // thread table.
  271. //
  272. Spinlock.ClaimLock();
  273. //
  274. // We need to duplicate the handle so we get
  275. // a real thread handle and not the pretend
  276. // ones supplied by NT.
  277. //
  278. if
  279. (
  280. DuplicateHandle
  281. (
  282. Process,
  283. Thread,
  284. Process,
  285. & NewHandle,
  286. DUPLICATE_SAME_ACCESS,
  287. False,
  288. DUPLICATE_SAME_ACCESS
  289. )
  290. )
  291. {
  292. //
  293. // We may need to expand the table if there are
  294. // a large number of threads.
  295. //
  296. while ( ActiveThreads >= MaxThreads )
  297. { Threads.Resize( (MaxThreads *= ExpandStore) ); }
  298. //
  299. // Add the thread handle to the table.
  300. //
  301. Threads[ ActiveThreads ++ ] = NewHandle;
  302. }
  303. else
  304. { Failure( "Failed to duplicate handle in RegisterThread" ); }
  305. //
  306. // We are finished so release the lock.
  307. //
  308. Spinlock.ReleaseLock();
  309. }
  310. /********************************************************************/
  311. /* */
  312. /* Set thread stack size. */
  313. /* */
  314. /* Set thread stack size. This will cause all new threads to */
  315. /* be created with the selected stack size. */
  316. /* */
  317. /********************************************************************/
  318. VOID THREAD::SetThreadStackSize( LONG Stack )
  319. {
  320. #ifdef DEBUGGING
  321. if ( Stack >= 0 )
  322. {
  323. #endif
  324. this -> Stack = Stack;
  325. #ifdef DEBUGGING
  326. }
  327. else
  328. { Failure( "Stack size in SetThreadStack()" ); }
  329. #endif
  330. }
  331. /********************************************************************/
  332. /* */
  333. /* Start a new thread. */
  334. /* */
  335. /* Start a new thread and configure it as requested by the */
  336. /* caller. If needed we will set the affinity and priority */
  337. /* of this thread later. */
  338. /* */
  339. /********************************************************************/
  340. BOOLEAN THREAD::StartThread( NEW_THREAD Function,VOID *Parameter,BOOLEAN Wait )
  341. {
  342. //
  343. // Wait for any pending thread creations to
  344. // complete.
  345. //
  346. if ( WaitForSingleObject( Started,INFINITE ) == WAIT_OBJECT_0 )
  347. {
  348. REGISTER unsigned NewStack = ((unsigned) Stack);
  349. //
  350. // Store the thread function and parameter
  351. // so they can be extracted later.
  352. //
  353. ThreadFunction = Function;
  354. ThreadParameter = Parameter;
  355. ThreadWait = Wait;
  356. //
  357. // Call the operating system to start the thread.
  358. //
  359. if ( _beginthread( NewThread,NewStack,((VOID*) this) ) != NULL )
  360. {
  361. //
  362. // Wait for the thread to initialize if needed.
  363. //
  364. return
  365. (
  366. (! Wait)
  367. ||
  368. (WaitForSingleObject( Running,INFINITE ) == WAIT_OBJECT_0)
  369. );
  370. }
  371. else
  372. { return False; }
  373. }
  374. else
  375. { return False; }
  376. }
  377. /********************************************************************/
  378. /* */
  379. /* Wait for threads. */
  380. /* */
  381. /* Wait for all threads to finish and then return. As this may */
  382. /* take a while an optional timeout may be supplied. */
  383. /* */
  384. /********************************************************************/
  385. BOOLEAN THREAD::WaitForThreads( LONG WaitTime )
  386. {
  387. REGISTER DWORD Wait = ((DWORD) WaitTime);
  388. return ( WaitForSingleObject( Completed,Wait ) != WAIT_TIMEOUT );
  389. }
  390. /********************************************************************/
  391. /* */
  392. /* Class destructor. */
  393. /* */
  394. /* Destory the thread class. This call is not thread safe */
  395. /* and should only be made in a single thread environment. */
  396. /* */
  397. /********************************************************************/
  398. THREAD::~THREAD( VOID )
  399. {
  400. Active = False;
  401. if
  402. (
  403. ! CloseHandle( Started )
  404. ||
  405. ! CloseHandle( Running )
  406. ||
  407. ! CloseHandle( Completed )
  408. )
  409. { Failure( "Event handles in destructor for THREAD" ); }
  410. }