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.

493 lines
12 KiB

  1. #include "precomp.h"
  2. //
  3. // SCH.CPP
  4. // Scheduler
  5. //
  6. // Copyright(c) Microsoft Corporation 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_CORE
  9. //
  10. //
  11. // SCH_Init - see sch.h
  12. //
  13. //
  14. BOOL SCH_Init(void)
  15. {
  16. BOOL rc = FALSE;
  17. DebugEntry(SCH_Init);
  18. ASSERT(!g_schEvent);
  19. ASSERT(!g_schThreadID);
  20. ASSERT(!g_schMessageOutstanding);
  21. //
  22. // Create g_schEvent with:
  23. // - default security descriptor
  24. // - auto-reset (resets when a thread is unblocked)
  25. // - initially signalled
  26. //
  27. g_schEvent = CreateEvent( NULL, FALSE, TRUE, SCH_EVENT_NAME );
  28. if (g_schEvent == NULL)
  29. {
  30. ERROR_OUT(( "Failed to create g_schEvent"));
  31. DC_QUIT;
  32. }
  33. InitializeCriticalSection(&g_schCriticalSection);
  34. g_schCurrentMode = SCH_MODE_ASLEEP;
  35. // lonchanc: do not start the scheduler as default
  36. // SCHSetMode(SCH_MODE_NORMAL);
  37. if (!DCS_StartThread(SCH_PacingProcessor))
  38. {
  39. ERROR_OUT(( "Failed to create SCH_PacingProcessor thread"));
  40. DC_QUIT;
  41. }
  42. ASSERT(g_schThreadID);
  43. rc = TRUE;
  44. DC_EXIT_POINT:
  45. DebugExitBOOL(SCH_Init, rc);
  46. return(rc);
  47. }
  48. //
  49. //
  50. // SCH_Term - see sch.h
  51. //
  52. //
  53. void SCH_Term(void)
  54. {
  55. DebugEntry(SCH_Term);
  56. //
  57. // This code needs to work even if SCH_Init hasn't been called or
  58. // failed in the middle.
  59. //
  60. if (g_schEvent)
  61. {
  62. if (g_schThreadID)
  63. {
  64. //
  65. // The scheduler thread exits its main loop when it spots that
  66. // g_schTerminating is TRUE. So all we have to do is ensure
  67. // that it runs its loop at least once more... It will clear g_schTerm-
  68. // inated just before exiting.
  69. //
  70. g_schTerminating = TRUE;
  71. SCH_ContinueScheduling(SCH_MODE_NORMAL);
  72. while (g_schTerminating)
  73. {
  74. Sleep(0);
  75. }
  76. ASSERT(!g_schThreadID);
  77. TRACE_OUT(("sch thread terminated"));
  78. //
  79. // Make sure we clear the message outstanding variable when
  80. // our thread exits.
  81. //
  82. g_schMessageOutstanding = FALSE;
  83. }
  84. DeleteCriticalSection(&g_schCriticalSection);
  85. CloseHandle(g_schEvent);
  86. g_schEvent = NULL;
  87. }
  88. DebugExitVOID(SCH_Term);
  89. }
  90. //
  91. //
  92. // SCH_ContinueScheduling - see sch.h
  93. //
  94. //
  95. void SCH_ContinueScheduling(UINT schedulingMode)
  96. {
  97. DebugEntry(SCH_ContinueScheduling);
  98. ASSERT( ((schedulingMode == SCH_MODE_NORMAL) ||
  99. (schedulingMode == SCH_MODE_TURBO)));
  100. EnterCriticalSection(&g_schCriticalSection); // lonchanc: need crit sect protection
  101. if (g_schCurrentMode == SCH_MODE_TURBO)
  102. {
  103. if (schedulingMode == SCH_MODE_TURBO)
  104. {
  105. SCHSetMode(schedulingMode);
  106. }
  107. DC_QUIT;
  108. }
  109. if (schedulingMode != g_schCurrentMode)
  110. {
  111. SCHSetMode(schedulingMode);
  112. }
  113. DC_EXIT_POINT:
  114. g_schStayAwake = TRUE;
  115. LeaveCriticalSection(&g_schCriticalSection); // lonchanc: need crit sect protection
  116. DebugExitVOID(SCH_ContinueScheduling);
  117. }
  118. //
  119. //
  120. // SCH_SchedulingMessageProcessed - see sch.h
  121. //
  122. //
  123. void SCH_SchedulingMessageProcessed()
  124. {
  125. DebugEntry(SCH_SchedulingMessageProcessed);
  126. g_schMessageOutstanding = FALSE;
  127. DebugExitVOID(SCH_SchedulingMessageProcessed);
  128. }
  129. //
  130. // Name: SCH_PacingProcessor
  131. //
  132. // Purpose: The main function executed by the scheduling thread.
  133. //
  134. // Returns: Zero.
  135. //
  136. // Params: syncObject - object to pass back to SetEvent
  137. //
  138. // Operation: The thread enters a main loop which continues while the
  139. // scheduler is initialized.
  140. //
  141. // The thread sets its priority to TIME_CRITICAL in order
  142. // that it runs as soon as possible when ready.
  143. //
  144. // The thread waits on an event (g_schEvent) with a timeout that
  145. // is set according to the current scheduler mode.
  146. //
  147. // The thread runs due to either:
  148. // - the timeout expiring, which is the normal periodic
  149. // scheduler behavior, or
  150. // - g_schEvent being signalled, which is how the scheduler is
  151. // woken from ASLEEP mode.
  152. //
  153. // The thread then posts a scheduler message the the Share Core
  154. // (if there is not one already outstanding) and loops back
  155. // to wait on g_schEvent.
  156. //
  157. // Changes in the scheduler mode are caused by calls to
  158. // SCH_ContinueScheduling updating variables accessed in this
  159. // routine, or by calculations made within the main loop of
  160. // this routine (e.g. TURBO mode timeout).
  161. //
  162. //
  163. DWORD WINAPI SCH_PacingProcessor(LPVOID hEventWait)
  164. {
  165. UINT rc = 0;
  166. DWORD rcWait;
  167. UINT timeoutPeriod;
  168. DebugEntry(SCH_PacingProcessor);
  169. //
  170. // Give ourselves the highest possible priority (within our process
  171. // priority class) to ensure that we run regularly to keep the
  172. // scheduling messages flowing.
  173. //
  174. if (!SetThreadPriority( GetCurrentThread(),
  175. THREAD_PRIORITY_TIME_CRITICAL ))
  176. {
  177. WARNING_OUT(( "SetThreadPriority failed"));
  178. }
  179. timeoutPeriod = g_schTimeoutPeriod;
  180. g_schThreadID = GetCurrentThreadId();
  181. //
  182. // Let the caller continue
  183. //
  184. SetEvent((HANDLE)hEventWait);
  185. //
  186. // Keep looping until the scheduler terminates.
  187. //
  188. while (!g_schTerminating)
  189. {
  190. //
  191. // Wait on g_schEvent with a timeout value that is set according
  192. // to the current scheduling mode.
  193. //
  194. // When we are active (NORMAL/TURBO scheduling) the timeout
  195. // period is a fraction of a second, so the normal behavior is
  196. // for this call to timeout, rather than be signalled.
  197. //
  198. rcWait = WaitForSingleObject(g_schEvent, timeoutPeriod);
  199. EnterCriticalSection(&g_schCriticalSection);
  200. if (g_schMessageOutstanding)
  201. {
  202. //
  203. // We must ensure that we post at least one scheduling message
  204. // before we can attempt to sleep - so force schStayAwake to
  205. // TRUE to keep us awake until we do post another message.
  206. //
  207. TRACE_OUT(( "Don't post message - one outstanding"));
  208. g_schStayAwake = TRUE;
  209. }
  210. //
  211. // If g_schEvent was signalled, then enter NORMAL scheduling mode.
  212. //
  213. if (rcWait == WAIT_OBJECT_0)
  214. {
  215. SCHSetMode(SCH_MODE_NORMAL);
  216. }
  217. else if (!g_schStayAwake)
  218. {
  219. TRACE_OUT(( "Sleep!"));
  220. SCHSetMode(SCH_MODE_ASLEEP);
  221. }
  222. else if ( (g_schCurrentMode == SCH_MODE_TURBO) &&
  223. ((GetTickCount() - g_schLastTurboModeSwitch) >
  224. SCH_TURBO_MODE_DURATION) )
  225. {
  226. //
  227. // Switch from turbo state back to normal state.
  228. //
  229. SCHSetMode(SCH_MODE_NORMAL);
  230. }
  231. //
  232. // Post the scheduling message - but only if there is not one
  233. // already outstanding.
  234. //
  235. if (!g_schMessageOutstanding && !g_schTerminating)
  236. {
  237. SCHPostSchedulingMessage();
  238. g_schStayAwake = FALSE;
  239. }
  240. timeoutPeriod = g_schTimeoutPeriod;
  241. LeaveCriticalSection(&g_schCriticalSection);
  242. }
  243. g_schThreadID = 0;
  244. g_schTerminating = FALSE;
  245. DebugExitDWORD(SCH_PacingProcessor, rc);
  246. return(rc);
  247. }
  248. //
  249. // Name: SCHPostSchedulingMessage
  250. //
  251. // Purpose: Posts the scheduling message to the main Share Core window.
  252. //
  253. // Returns: Nothing.
  254. //
  255. // Params: None.
  256. //
  257. //
  258. void SCHPostSchedulingMessage(void)
  259. {
  260. DebugEntry(SCHPostSchedulingMessage);
  261. if (PostMessage( g_asMainWindow, DCS_PERIODIC_SCHEDULE_MSG, 0, 0 ))
  262. {
  263. g_schMessageOutstanding = TRUE;
  264. }
  265. DebugExitVOID(SCHPostSchedulingMessage);
  266. }
  267. //
  268. // Name: SCHSetMode
  269. //
  270. // Purpose: Sets the current scheduler mode - and wakes the scheduler
  271. // thread if necessary.
  272. //
  273. // Returns: Nothing.
  274. //
  275. // Params: newMode
  276. //
  277. //
  278. void SCHSetMode(UINT newMode)
  279. {
  280. DebugEntry(SCHSetMode);
  281. ASSERT( ((newMode == SCH_MODE_ASLEEP) ||
  282. (newMode == SCH_MODE_NORMAL) ||
  283. (newMode == SCH_MODE_TURBO) ));
  284. EnterCriticalSection(&g_schCriticalSection);
  285. TRACE_OUT(( "Switching from state %u -> %u", g_schCurrentMode, newMode));
  286. if (newMode == SCH_MODE_TURBO)
  287. {
  288. g_schLastTurboModeSwitch = GetTickCount();
  289. }
  290. if (g_schCurrentMode == SCH_MODE_ASLEEP)
  291. {
  292. //
  293. // Wake up the scheduler.
  294. //
  295. TRACE_OUT(( "Waking up scheduler - SetEvent"));
  296. if (!SetEvent(g_schEvent))
  297. {
  298. ERROR_OUT(( "Failed SetEvent(%#x)", g_schEvent));
  299. }
  300. }
  301. g_schCurrentMode = newMode;
  302. g_schTimeoutPeriod = (newMode == SCH_MODE_ASLEEP) ? INFINITE :
  303. ((newMode == SCH_MODE_NORMAL) ? SCH_PERIOD_NORMAL :
  304. SCH_PERIOD_TURBO);
  305. LeaveCriticalSection(&g_schCriticalSection);
  306. DebugExitVOID(SCHSetMode);
  307. }
  308. //
  309. // DCS_StartThread(...)
  310. //
  311. // See ut.h
  312. //
  313. // DESCRIPTION:
  314. // ============
  315. // Start a new thread.
  316. //
  317. // PARAMETERS:
  318. // ===========
  319. // entryFunction : A pointer to the thread entry point.
  320. // timeout : timeout in milliseconds
  321. //
  322. // RETURNS:
  323. // ========
  324. // Nothing.
  325. //
  326. //
  327. BOOL DCS_StartThread
  328. (
  329. LPTHREAD_START_ROUTINE entryFunction
  330. )
  331. {
  332. BOOL rc = FALSE;
  333. HANDLE hndArray[2];
  334. DWORD tid;
  335. DWORD dwrc;
  336. DebugEntry(DCS_StartThread);
  337. //
  338. // The event handle ( hndArray[0] ) is initialized in the call to CreateEvent,
  339. // but in the case where that fails, we would try to CloseHandle on
  340. // a garbage hndArray[1]. So we have to initialize the ThreadHandle
  341. //
  342. hndArray[1] = 0;
  343. //
  344. // Create event - initially non-signalled; manual control.
  345. //
  346. hndArray[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
  347. if (hndArray[0] == 0)
  348. {
  349. ERROR_OUT(("Failed to create event: sys rc %lu", GetLastError()));
  350. DC_QUIT;
  351. }
  352. TRACE_OUT(("Event 0x%08x created - now create thread", hndArray[0]));
  353. //
  354. // Start a new thread to run the DC-Share core task.
  355. // Use C runtime (which calls CreateThread) to avoid memory leaks.
  356. //
  357. hndArray[1] = CreateThread(NULL, 0, entryFunction, (LPVOID)hndArray[0],
  358. 0, &tid);
  359. if (hndArray[1] == 0)
  360. {
  361. //
  362. // Failed!
  363. //
  364. ERROR_OUT(("Failed to create thread: sys rc %lu", GetLastError()));
  365. DC_QUIT;
  366. }
  367. TRACE_OUT(("Thread 0x%08x created - now wait signal", hndArray[1]));
  368. //
  369. // Wait for thread exit or event to be set.
  370. //
  371. dwrc = WaitForMultipleObjects(2, hndArray, FALSE, INFINITE);
  372. switch (dwrc)
  373. {
  374. case WAIT_OBJECT_0:
  375. //
  376. // Event triggered - thread initialised OK.
  377. //
  378. TRACE_OUT(("event signalled"));
  379. rc = TRUE;
  380. break;
  381. case WAIT_OBJECT_0 + 1:
  382. ERROR_OUT(("Thread exited with rc"));
  383. break;
  384. case WAIT_TIMEOUT:
  385. TRACE_OUT(("Wait timeout"));
  386. break;
  387. default:
  388. TRACE_OUT(("Wait returned %d", dwrc));
  389. break;
  390. }
  391. DC_EXIT_POINT:
  392. //
  393. // Destroy event object.
  394. //
  395. if (hndArray[0] != 0)
  396. {
  397. TRACE_OUT(("Destroy event object"));
  398. CloseHandle(hndArray[0]);
  399. }
  400. //
  401. // Destroy thread handle object.
  402. //
  403. if (hndArray[1] != 0)
  404. {
  405. TRACE_OUT(("Destroy thread handle object"));
  406. CloseHandle(hndArray[1]);
  407. }
  408. DebugExitBOOL(DCS_StartThread, rc);
  409. return(rc);
  410. }