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.

939 lines
27 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: runobj.cxx
  7. //
  8. // Contents: Run instance object class implementations.
  9. //
  10. // Classes: CRun and CRunList
  11. //
  12. // History: 14-Mar-96 EricB Created.
  13. // 10-Nov-96 AnirudhS Fixed CRunList::AddSorted to discard the
  14. // appropriate element if the list is at its maximum size.
  15. // Fixed CRunList::MakeSysTimeArray to call CoTaskMemAlloc
  16. // once instead of calling CoTaskMemRealloc in a loop.
  17. //
  18. //----------------------------------------------------------------------------
  19. #include "..\pch\headers.hxx"
  20. #pragma hdrstop
  21. #include <job_cls.hxx>
  22. #include <misc.hxx>
  23. #include <debug.hxx>
  24. #include "..\svc_core\svc_core.hxx"
  25. #include <userenv.h> // UnloadUserProfile
  26. PFNSetThreadExecutionState pfnSetThreadExecutionState;
  27. DWORD g_WakeCountSlot = 0xFFFFFFFF;
  28. //+----------------------------------------------------------------------------
  29. //
  30. // Run instance object class
  31. //
  32. //-----------------------------------------------------------------------------
  33. //+----------------------------------------------------------------------------
  34. //
  35. // Method: CRun::CRun
  36. //
  37. // Synopsis: ctor for time-sorted lists.
  38. //
  39. //-----------------------------------------------------------------------------
  40. CRun::CRun(LPFILETIME pft, LPFILETIME pftDeadline, FILETIME ftKill,
  41. DWORD MaxRunTime, DWORD rgFlags, WORD wIdleWait,
  42. BOOL fKeepAfterRunning) :
  43. m_ft(*pft),
  44. m_ftDeadline(*pftDeadline),
  45. m_ftKill(ftKill),
  46. m_hJob(NULL),
  47. m_ptszJobName(NULL),
  48. m_dwProcessId(0),
  49. m_hUserToken(NULL),
  50. m_ptszDesktop(NULL),
  51. m_ptszStation(NULL),
  52. m_hProfile(NULL),
  53. m_rgFlags(rgFlags),
  54. m_dwMaxRunTime(MaxRunTime),
  55. m_wIdleWait(wIdleWait),
  56. m_fKeepInList(fKeepAfterRunning),
  57. m_fStarted(FALSE),
  58. m_bCloseUserHandle(FALSE)
  59. {
  60. schDebugOut((DEB_TRACE, "CRun::CRun(0x%x)\n", this));
  61. }
  62. //+----------------------------------------------------------------------------
  63. //
  64. // Method: CRun::CRun
  65. //
  66. // Synopsis: ctor for non-time-sorted lists.
  67. //
  68. //-----------------------------------------------------------------------------
  69. CRun::CRun(DWORD MaxRunTime, DWORD rgFlags, FILETIME ftDeadline,
  70. BOOL fKeepAfterRunning) :
  71. m_ftDeadline(ftDeadline),
  72. m_ftKill(MAX_FILETIME),
  73. m_hJob(NULL),
  74. m_ptszJobName(NULL),
  75. m_dwProcessId(0),
  76. m_ptszDesktop(NULL),
  77. m_ptszStation(NULL),
  78. m_hUserToken(NULL),
  79. m_hProfile(NULL),
  80. m_rgFlags(rgFlags),
  81. m_dwMaxRunTime(MaxRunTime),
  82. m_wIdleWait(0),
  83. m_fKeepInList(fKeepAfterRunning),
  84. m_fStarted(FALSE),
  85. m_bCloseUserHandle(FALSE)
  86. {
  87. //schDebugOut((DEB_TRACE, "CRun::CRun(0x%x)\n", this));
  88. //
  89. // This ctor is used for non-sorted lists. Set the time elements to
  90. // non-zero values to distinguish these elements from the head.
  91. //
  92. // CODEWORK - Don't use 0,0 to mark the head. Remove IsNull() method.
  93. // Instead use a NULL Next pointer to mark the last list element.
  94. //
  95. m_ft.dwLowDateTime = 1;
  96. m_ft.dwHighDateTime = 1;
  97. }
  98. //+----------------------------------------------------------------------------
  99. //
  100. // Method: CRun::CRun
  101. //
  102. // Synopsis: ctor for idle-time-sorted lists.
  103. //
  104. //-----------------------------------------------------------------------------
  105. CRun::CRun(DWORD MaxRunTime, DWORD rgFlags, WORD wIdleWait,
  106. FILETIME ftDeadline, BOOL fKeepAfterRunning) :
  107. m_ftDeadline(ftDeadline),
  108. m_ftKill(MAX_FILETIME),
  109. m_hJob(NULL),
  110. m_ptszJobName(NULL),
  111. m_dwProcessId(0),
  112. m_ptszDesktop(NULL),
  113. m_ptszStation(NULL),
  114. m_hUserToken(NULL),
  115. m_hProfile(NULL),
  116. m_rgFlags(rgFlags),
  117. m_dwMaxRunTime(MaxRunTime),
  118. m_wIdleWait(wIdleWait),
  119. m_fKeepInList(fKeepAfterRunning),
  120. m_fStarted(FALSE),
  121. m_bCloseUserHandle(FALSE)
  122. {
  123. TRACE3(CRun,CRun);
  124. //
  125. // Set the time elements to non-zero values to distinguish
  126. // these elements from the head.
  127. // CODEWORK - as above, don't do this.
  128. //
  129. m_ft.dwLowDateTime = 1;
  130. m_ft.dwHighDateTime = 1;
  131. }
  132. //+----------------------------------------------------------------------------
  133. //
  134. // Method: CRun::CRun
  135. //
  136. // Synopsis: copy ctor.
  137. //
  138. // Notes: This ctor should not be used to copy running objects, i.e.
  139. // objects that have valid process, user token, or profile
  140. // handles.
  141. //
  142. //-----------------------------------------------------------------------------
  143. CRun::CRun(CRun * pRun) :
  144. m_ft(pRun->m_ft),
  145. m_ftDeadline(pRun->m_ftDeadline),
  146. m_ftKill(pRun->m_ftKill),
  147. m_hJob(NULL),
  148. m_ptszJobName(NULL),
  149. m_dwProcessId(pRun->m_dwProcessId),
  150. m_ptszDesktop(NULL),
  151. m_ptszStation(NULL),
  152. m_hUserToken(NULL),
  153. m_hProfile(NULL),
  154. m_rgFlags(pRun->m_rgFlags),
  155. m_dwMaxRunTime(pRun->m_dwMaxRunTime),
  156. m_wIdleWait(pRun->m_wIdleWait),
  157. m_fKeepInList(pRun->m_fKeepInList),
  158. m_fStarted(pRun->m_fStarted),
  159. m_bCloseUserHandle(FALSE)
  160. {
  161. TRACE3(CRun,CRun(Copy));
  162. SetName(pRun->m_ptszJobName);
  163. schAssert(!pRun->m_hJob);
  164. schAssert(!pRun->m_hUserToken);
  165. schAssert(!pRun->m_hProfile);
  166. }
  167. //+---------------------------------------------------------------------------
  168. //
  169. // Method: CRun::CRun
  170. //
  171. // Synopsis: ctor
  172. //
  173. //----------------------------------------------------------------------------
  174. CRun::CRun(void) :
  175. m_ftDeadline(MAX_FILETIME),
  176. m_ftKill(MAX_FILETIME),
  177. m_hJob(NULL),
  178. m_ptszJobName(NULL),
  179. m_dwProcessId(0),
  180. m_ptszDesktop(NULL),
  181. m_ptszStation(NULL),
  182. m_hUserToken(NULL),
  183. m_hProfile(NULL),
  184. m_rgFlags(0),
  185. m_dwMaxRunTime(RUN_TIME_NO_END),
  186. m_wIdleWait(0),
  187. m_fKeepInList(FALSE),
  188. m_fStarted(FALSE),
  189. m_bCloseUserHandle(FALSE)
  190. {
  191. //schDebugOut((DEB_TRACE, "CRun::CRun(0x%x)\n", this));
  192. //
  193. // The null arg ctor is used only by CRunList for its head element
  194. // member. The zero time value for this element marks it as the head
  195. // when traversing the doubly linked list.
  196. //
  197. m_ft.dwLowDateTime = 0;
  198. m_ft.dwHighDateTime = 0;
  199. }
  200. //+---------------------------------------------------------------------------
  201. //
  202. // Method: CRun::~CRun
  203. //
  204. // Synopsis: dtor
  205. //
  206. //----------------------------------------------------------------------------
  207. CRun::~CRun()
  208. {
  209. BOOL fOk;
  210. //schDebugOut((DEB_TRACE, "CRun::~CRun(0x%x)\n", this));
  211. if (m_hJob)
  212. {
  213. CloseHandle(m_hJob);
  214. }
  215. if (m_ptszJobName)
  216. {
  217. delete m_ptszJobName;
  218. }
  219. if (m_hProfile)
  220. {
  221. fOk = UnloadUserProfile(m_hUserToken, m_hProfile);
  222. if (!fOk)
  223. {
  224. ERR_OUT("~CRun: UnloadUserProfile",
  225. HRESULT_FROM_WIN32(GetLastError()));
  226. }
  227. }
  228. if (m_hUserToken && m_bCloseUserHandle)
  229. {
  230. fOk = CloseHandle(m_hUserToken);
  231. if (!fOk)
  232. {
  233. ERR_OUT("~CRun: CloseHandle",
  234. HRESULT_FROM_WIN32(GetLastError()));
  235. }
  236. }
  237. if ( m_ptszDesktop )
  238. {
  239. delete m_ptszDesktop;
  240. }
  241. if ( m_ptszStation )
  242. {
  243. delete m_ptszStation;
  244. }
  245. }
  246. //+---------------------------------------------------------------------------
  247. //
  248. // Method: CRun::SetName
  249. //
  250. // Synopsis: Set the job name property. This is the folder-relative name.
  251. //
  252. //----------------------------------------------------------------------------
  253. HRESULT
  254. CRun::SetName(LPCTSTR ptszName)
  255. {
  256. if (m_ptszJobName)
  257. {
  258. delete m_ptszJobName;
  259. m_ptszJobName = NULL;
  260. }
  261. if (!ptszName)
  262. {
  263. return S_OK;
  264. }
  265. size_t cchBuff = lstrlen(ptszName) + 1;
  266. m_ptszJobName = new TCHAR[cchBuff];
  267. if (m_ptszJobName == NULL)
  268. {
  269. return(E_OUTOFMEMORY);
  270. }
  271. StringCchCopy(m_ptszJobName, cchBuff, ptszName);
  272. return(S_OK);
  273. }
  274. //+---------------------------------------------------------------------------
  275. //
  276. // Method: CRun::SetDesktop
  277. //
  278. // Synopsis: Set the Desktop name property. This is the windows station \ desktop.
  279. //
  280. //----------------------------------------------------------------------------
  281. HRESULT
  282. CRun::SetDesktop( LPCTSTR ptszDesktop )
  283. {
  284. if (m_ptszDesktop)
  285. {
  286. delete m_ptszDesktop;
  287. m_ptszDesktop = NULL;
  288. }
  289. if (!ptszDesktop)
  290. {
  291. return S_OK;
  292. }
  293. size_t cchBuff = lstrlen(ptszDesktop) + 1;
  294. m_ptszDesktop = new TCHAR[cchBuff];
  295. if (m_ptszDesktop == NULL)
  296. {
  297. return(E_OUTOFMEMORY);
  298. }
  299. StringCchCopy(m_ptszDesktop, cchBuff, ptszDesktop);
  300. return(S_OK);
  301. }
  302. //+---------------------------------------------------------------------------
  303. //
  304. // Method: CRun::SetStation
  305. //
  306. // Synopsis: Set the Desktop name property. This is the windows station \ desktop.
  307. //
  308. //----------------------------------------------------------------------------
  309. HRESULT
  310. CRun::SetStation( LPCTSTR ptszStation )
  311. {
  312. if (m_ptszStation)
  313. {
  314. delete m_ptszStation;
  315. m_ptszStation = NULL;
  316. }
  317. if (!ptszStation)
  318. {
  319. return S_OK;
  320. }
  321. size_t cchBuff = lstrlen(ptszStation) + 1;
  322. m_ptszStation = new TCHAR[cchBuff];
  323. if (m_ptszStation == NULL)
  324. {
  325. return(E_OUTOFMEMORY);
  326. }
  327. StringCchCopy(m_ptszStation, cchBuff, ptszStation);
  328. return(S_OK);
  329. }
  330. //+---------------------------------------------------------------------------
  331. //
  332. // Method: CRun::AdjustKillTimeByMaxRunTime
  333. //
  334. // Synopsis: If the job has a max run time, advance its kill time to "now"
  335. // plus the max run time.
  336. //
  337. //----------------------------------------------------------------------------
  338. void
  339. CRun::AdjustKillTimeByMaxRunTime(FILETIME ftNow)
  340. {
  341. if (m_dwMaxRunTime != INFINITE)
  342. {
  343. AdvanceKillTime(FTfrom64(
  344. FTto64(ftNow) +
  345. (DWORDLONG) m_dwMaxRunTime *
  346. FILETIMES_PER_MILLISECOND));
  347. }
  348. }
  349. //+----------------------------------------------------------------------------
  350. //
  351. // Run object list class
  352. //
  353. //-----------------------------------------------------------------------------
  354. //+----------------------------------------------------------------------------
  355. //
  356. // Member: CRunList::FreeList
  357. //
  358. // Synopsis: Frees the linked list elements, skipping the head.
  359. //
  360. //-----------------------------------------------------------------------------
  361. void
  362. CRunList::FreeList(void)
  363. {
  364. //
  365. // Skip the head, it is a placeholder in the circular list with a time
  366. // value of zero. The zero time value is used as a marker so that we can
  367. // tell when we have traversed the entire list.
  368. //
  369. CRun * pCur = m_RunHead.Next();
  370. while (!pCur->IsNull())
  371. {
  372. CRun * pNext = pCur->Next();
  373. pCur->UnLink();
  374. delete pCur;
  375. pCur = pNext;
  376. }
  377. }
  378. //+----------------------------------------------------------------------------
  379. //
  380. // Member: CRunList::AddSorted
  381. //
  382. // Synopsis: Add to the list in time sorted order.
  383. //
  384. // Arguments: [ftRun] -
  385. // [ftDeadline] -
  386. // [ftKillTime] -
  387. // [ptszJobName] -
  388. // [dwJobFlags] -
  389. // [dwMaxRunTime] -
  390. // [wIdleWait] -
  391. // [pCount] - On entry and on exit, points to the number of
  392. // elements in the list.
  393. // [cLimit] - Limit on the number of elements in the list.
  394. //
  395. // Returns: S_OK - new run added to the list.
  396. // S_FALSE - new run not added to the list because the list has
  397. // already reached its size limit and the new job's run time
  398. // is later than the last run time in the list.
  399. //
  400. //-----------------------------------------------------------------------------
  401. HRESULT
  402. CTimeRunList::AddSorted(FILETIME ftRun, FILETIME ftDeadline, FILETIME ftKillTime,
  403. LPTSTR ptszJobName,
  404. DWORD dwJobFlags, DWORD dwMaxRunTime, WORD wIdleWait,
  405. WORD * pCount, WORD cLimit)
  406. {
  407. schAssert(*pCount <= cLimit);
  408. //
  409. // The list is monotonically increasing in time. Traverse the list in
  410. // reverse order since the most common case will be to put the new
  411. // element at the end. That is, except in the case of overlapping
  412. // duration intervals, the run times for the same trigger will be
  413. // discovered in monotonically increasing order.
  414. //
  415. // For merging in the run times from separate triggers or jobs, the runs
  416. // will not be in any predictable order. In this case, it doesn't matter
  417. // from which end the search starts.
  418. //
  419. // CODEWORK Use IsNull() instead of GetTime(). Make this loop a for loop.
  420. //
  421. FILETIME ftCur;
  422. CRun * pRun = m_RunHead.Prev();
  423. pRun->GetTime(&ftCur);
  424. //
  425. // Note that the head element is merely a marker (since this is a doubly
  426. // linked, circular list) and has its time value set to zero. Thus if we
  427. // reach a zero FILETIME, we have reached the head and thus know that
  428. // there is no list element with a later time, so insert at the tail.
  429. //
  430. while (ftCur.dwLowDateTime || ftCur.dwHighDateTime)
  431. {
  432. if (CompareFileTime(&ftCur, &ftRun) == 0)
  433. {
  434. //
  435. // Duplicate found, check for job name match. If here as a result
  436. // of a call to ITask::GetRunTimes, then both will be null. We
  437. // want duplicates eliminated in this case. Otherwise, compare
  438. // names.
  439. //
  440. if ((pRun->GetName() == NULL && ptszJobName == NULL) ||
  441. (pRun->GetName() != NULL && ptszJobName != NULL &&
  442. lstrcmpi(pRun->GetName(), ptszJobName) == 0))
  443. {
  444. // keep the one already in the list but set the kill time
  445. // to the earlier of the two,
  446. // set the idle wait time to the lesser (less restrictive)
  447. // of the two
  448. // and set the start deadline to the later (less
  449. // restrictive) of the two.
  450. //
  451. pRun->ReduceWaitTo(wIdleWait);
  452. pRun->AdvanceKillTime(ftKillTime);
  453. pRun->RelaxDeadline(ftDeadline);
  454. // (There is no reason for the MaxRunTime to be different)
  455. schAssert(pRun->GetMaxRunTime() == dwMaxRunTime);
  456. return S_OK;
  457. }
  458. }
  459. if (CompareFileTime(&ftCur, &ftRun) < 0)
  460. {
  461. //
  462. // The new run is later than the current, so we are at the
  463. // insertion point.
  464. //
  465. break;
  466. }
  467. pRun = pRun->Prev();
  468. pRun->GetTime(&ftCur);
  469. }
  470. //
  471. // If the list is already at its maximum size, discard either the
  472. // last element or the one we were about to insert, whichever is
  473. // later.
  474. //
  475. if (*pCount >= cLimit)
  476. {
  477. CRun * pLast = m_RunHead.Prev();
  478. if (pLast == pRun)
  479. {
  480. //
  481. // We were about to insert after the last element.
  482. //
  483. return S_FALSE;
  484. }
  485. else
  486. {
  487. //
  488. // Discard the last element before inserting the new one.
  489. //
  490. pLast->UnLink();
  491. delete pLast;
  492. (*pCount)--;
  493. }
  494. }
  495. //
  496. // Create the new element and insert after the current one.
  497. //
  498. CRun * pNewRun = new CRun(&ftRun, &ftDeadline, ftKillTime, dwMaxRunTime,
  499. dwJobFlags, wIdleWait, FALSE);
  500. if (!pNewRun)
  501. {
  502. ERR_OUT("RunList: Add", E_OUTOFMEMORY);
  503. return E_OUTOFMEMORY;
  504. }
  505. HRESULT hr = pNewRun->SetName(ptszJobName);
  506. if (FAILED(hr))
  507. {
  508. ERR_OUT("CRunList::AddSorted SetName", hr);
  509. delete pNewRun;
  510. return hr;
  511. }
  512. pNewRun->SetNext(pRun->Next());
  513. pNewRun->Next()->SetPrev(pNewRun);
  514. pRun->SetNext(pNewRun);
  515. pNewRun->SetPrev(pRun);
  516. //
  517. // Increment the count.
  518. //
  519. (*pCount)++;
  520. return S_OK;
  521. }
  522. //+----------------------------------------------------------------------------
  523. //
  524. // Member: CIdleRunList::AddSortedByIdleWait
  525. //
  526. // Synopsis: Add to the list in time sorted order.
  527. //
  528. //-----------------------------------------------------------------------------
  529. void
  530. CIdleRunList::AddSortedByIdleWait(CRun * pAdd)
  531. {
  532. //
  533. // If the system needs to stay awake to run this task, increment the
  534. // thread's wake count. (We know that this is always called by the
  535. // worker thread.)
  536. //
  537. if (pAdd->IsFlagSet(TASK_FLAG_SYSTEM_REQUIRED))
  538. {
  539. WrapSetThreadExecutionState(TRUE, "AddSortedByIdleWait");
  540. }
  541. if (m_RunHead.Next()->IsNull())
  542. {
  543. // List is empty, so add this as the first element.
  544. //
  545. pAdd->LinkAfter(&m_RunHead);
  546. return;
  547. }
  548. WORD wAddWait = pAdd->GetWait();
  549. schAssert(wAddWait > 0); // We should never put a job in the idle wait
  550. // list if its idle wait time is 0
  551. //
  552. // Walk the list, comparing idle wait times.
  553. //
  554. CRun * pCur = m_RunHead.Next();
  555. while (!pCur->IsNull())
  556. {
  557. if (wAddWait < pCur->GetWait())
  558. {
  559. pAdd->LinkBefore(pCur);
  560. return;
  561. }
  562. pCur = pCur->Next();
  563. }
  564. //
  565. // Add to the end of the list.
  566. //
  567. pAdd->LinkBefore(pCur);
  568. }
  569. //+----------------------------------------------------------------------------
  570. //
  571. // Member: CIdleRunList::GetFirstWait
  572. //
  573. // Synopsis: Finds the lowest idle wait time of the jobs in the list that
  574. // haven't already been started in this idle period.
  575. // Returns 0xffff if there is no such job.
  576. //
  577. //-----------------------------------------------------------------------------
  578. WORD
  579. CIdleRunList::GetFirstWait()
  580. {
  581. for (CRun * pRun = m_RunHead.Next();
  582. !pRun->IsNull();
  583. pRun = pRun->Next())
  584. {
  585. if (!pRun->m_fStarted)
  586. {
  587. // (We should never have inserted a run with zero wait time)
  588. schAssert(pRun->GetWait() != 0);
  589. return (pRun->GetWait());
  590. }
  591. }
  592. return 0xffff;
  593. }
  594. //+----------------------------------------------------------------------------
  595. //
  596. // Member: CIdleRunList::MarkNoneStarted
  597. //
  598. // Synopsis: Marks all jobs in the idle list as not having been started in
  599. // the current idle period.
  600. //
  601. //-----------------------------------------------------------------------------
  602. void
  603. CIdleRunList::MarkNoneStarted()
  604. {
  605. schDebugOut((DEB_IDLE, "Marking idle jobs as not started\n"));
  606. for (CRun * pRun = GetFirstJob();
  607. !pRun->IsNull();
  608. pRun = pRun->Next())
  609. {
  610. pRun->m_fStarted = FALSE;
  611. }
  612. }
  613. //+----------------------------------------------------------------------------
  614. //
  615. // Member: CRunList::AddCopy
  616. //
  617. // Synopsis: Add a copy of the object to the list.
  618. //
  619. //-----------------------------------------------------------------------------
  620. HRESULT
  621. CRunList::AddCopy(CRun * pOriginal)
  622. {
  623. CRun * pCopy = new CRun(pOriginal);
  624. if (pCopy == NULL)
  625. {
  626. return E_OUTOFMEMORY;
  627. }
  628. pCopy->LinkAfter(&m_RunHead);
  629. return S_OK;
  630. }
  631. //+----------------------------------------------------------------------------
  632. //
  633. // Member: CTimeRunList::Pop
  634. //
  635. // Synopsis: Removes the first (earliest) time element from the list and
  636. // returns it.
  637. //
  638. //-----------------------------------------------------------------------------
  639. CRun *
  640. CTimeRunList::Pop(void)
  641. {
  642. CRun * pPop = m_RunHead.Next();
  643. if (pPop->IsNull())
  644. {
  645. // List is empty, so return a flag return code.
  646. //
  647. return NULL;
  648. }
  649. pPop->UnLink();
  650. return pPop;
  651. }
  652. //+----------------------------------------------------------------------------
  653. //
  654. // Member: CTimeRunList::PeekHeadTime
  655. //
  656. // Synopsis: Returns the filetime value for the element at the head of the
  657. // list.
  658. //
  659. //-----------------------------------------------------------------------------
  660. HRESULT
  661. CTimeRunList::PeekHeadTime(LPFILETIME pft)
  662. {
  663. if (m_RunHead.Next()->IsNull())
  664. {
  665. // List is empty, so return a flag return code.
  666. //
  667. return S_FALSE;
  668. }
  669. m_RunHead.Next()->GetTime(pft);
  670. return S_OK;
  671. }
  672. //+----------------------------------------------------------------------------
  673. //
  674. // Function: CTimeRunList::MakeSysTimeArray
  675. //
  676. // Synopsis: returns the run list times as an array of SYSTEMTIME structs.
  677. //
  678. // Arguments: [prgst] - a pointer to the returned array of filetime structs
  679. // is stored here. This function allocates the array
  680. // using CoTaskMemAlloc. It must be freed by the caller.
  681. // [pCount] - On entry, points to an upper limit on the number of
  682. // array elements to return. On exit, points to the
  683. // actual number returned.
  684. //
  685. // Returns: E_OUTOFMEMORY, S_OK
  686. //
  687. //-----------------------------------------------------------------------------
  688. HRESULT
  689. CTimeRunList::MakeSysTimeArray(LPSYSTEMTIME * prgst, WORD * pCount)
  690. {
  691. WORD cLimit = *pCount;
  692. *pCount = 0;
  693. *prgst = (LPSYSTEMTIME) CoTaskMemAlloc(cLimit * sizeof(SYSTEMTIME));
  694. if (*prgst == NULL)
  695. {
  696. return E_OUTOFMEMORY;
  697. }
  698. //
  699. // Skip the head, it is a placeholder in the circular list with a time
  700. // value of zero.
  701. //
  702. for (CRun * pCur = m_RunHead.Next();
  703. (*pCount < cLimit) && (!pCur->IsNull());
  704. (*pCount)++, pCur = pCur->Next())
  705. {
  706. pCur->GetSysTime( &(*prgst)[*pCount] );
  707. }
  708. return S_OK;
  709. }
  710. //+----------------------------------------------------------------------------
  711. //
  712. // Member: CIdleRunList::FreeList
  713. //
  714. // Synopsis: Same as CRunList::FreeList except it decrements the thread's
  715. // wake count for each system-required run in the list. (We
  716. // know this method is only called by the worker thread.)
  717. //
  718. //-----------------------------------------------------------------------------
  719. void
  720. CIdleRunList::FreeList()
  721. {
  722. CRun * pCur = m_RunHead.Next();
  723. while (!pCur->IsNull())
  724. {
  725. CRun * pNext = pCur->Next();
  726. pCur->UnLink();
  727. if (pCur->IsFlagSet(TASK_FLAG_SYSTEM_REQUIRED))
  728. {
  729. WrapSetThreadExecutionState(FALSE, "CIdleRunList::FreeList");
  730. }
  731. delete pCur;
  732. pCur = pNext;
  733. }
  734. }
  735. //+----------------------------------------------------------------------------
  736. //
  737. // Member: CIdleRunList::FreeExpiredOrRegenerated
  738. //
  739. // Synopsis: This method is called when rebuilding the idle wait list from
  740. // the data in the tasks folder.
  741. // Removes runs that have m_fKeepInList set. (These correspond
  742. // to jobs with idle triggers.) Also purges expired runs.
  743. // Runs that don't have m_fKeepInList set correspond to runs that
  744. // have been triggered due to some other event, and are waiting
  745. // for an idle period; these are not removed here.
  746. //
  747. //-----------------------------------------------------------------------------
  748. void
  749. CIdleRunList::FreeExpiredOrRegenerated()
  750. {
  751. // BUGBUG ftNow should be a parameter
  752. FILETIME ftNow = GetLocalTimeAsFileTime();
  753. CRun * pNext;
  754. for (CRun *pRun = m_RunHead.Next();
  755. !pRun->IsNull();
  756. pRun = pNext)
  757. {
  758. pNext = pRun->Next();
  759. if (pRun->IsIdleTriggered() ||
  760. CompareFileTime(pRun->GetDeadline(), &ftNow) < 0)
  761. {
  762. pRun->UnLink();
  763. //
  764. // If the system needed to stay awake to run this task, decrement
  765. // the thread's wake count. (We know that this is always called
  766. // by the worker thread.)
  767. //
  768. if (pRun->IsFlagSet(TASK_FLAG_SYSTEM_REQUIRED))
  769. {
  770. WrapSetThreadExecutionState(FALSE,
  771. "CIdleRunList::FreeExpiredOrRegenerated");
  772. }
  773. delete pRun;
  774. }
  775. }
  776. }
  777. //+----------------------------------------------------------------------------
  778. //
  779. // Function: WrapSetThreadExecutionStateFn
  780. //
  781. // Synopsis: Wrapper for dynamically loaded function
  782. //
  783. //-----------------------------------------------------------------------------
  784. void WINAPI
  785. WrapSetThreadExecutionStateFn(
  786. BOOL fSystemRequired
  787. #if DBG
  788. , LPCSTR pszDbgMsg // parameter for debug output message
  789. #endif
  790. )
  791. {
  792. DWORD dwCount = (DWORD) (ULONG_PTR)TlsGetValue(g_WakeCountSlot);
  793. if (fSystemRequired)
  794. {
  795. //
  796. // Increment this thread's keep-awake count. If it was zero,
  797. // set the system-required state.
  798. //
  799. schDebugOut((DEB_USER5, "INCREMENTING keep-awake count to %ld: %s\n",
  800. dwCount + 1, pszDbgMsg));
  801. schAssert(dwCount != (DWORD) -1);
  802. dwCount++;
  803. if (dwCount == 1)
  804. {
  805. if (pfnSetThreadExecutionState != NULL)
  806. {
  807. schDebugOut((DEB_USER5, "SETTING sys-required state\n"));
  808. (pfnSetThreadExecutionState)(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
  809. }
  810. }
  811. }
  812. else
  813. {
  814. //
  815. // Decrement this thread's keep-awake count. If it becomes zero,
  816. // reset the system-required state.
  817. //
  818. schDebugOut((DEB_USER5, "DECREMENTING keep-awake count to %ld: %s\n",
  819. dwCount - 1, pszDbgMsg));
  820. schAssert(dwCount != 0);
  821. dwCount--;
  822. if (dwCount == 0)
  823. {
  824. if (pfnSetThreadExecutionState != NULL)
  825. {
  826. schDebugOut((DEB_USER5, "RESETTING sys-required state\n"));
  827. (pfnSetThreadExecutionState)(ES_CONTINUOUS);
  828. }
  829. }
  830. }
  831. if (!TlsSetValue(g_WakeCountSlot, UlongToPtr(dwCount)))
  832. {
  833. ERR_OUT("TlsSetValue", GetLastError());
  834. }
  835. }
  836. //+----------------------------------------------------------------------------
  837. //
  838. // Function: InitThreadWakeCount
  839. //
  840. // Synopsis: Initialize this thread's keep-awake count.
  841. //
  842. //-----------------------------------------------------------------------------
  843. void
  844. InitThreadWakeCount()
  845. {
  846. schDebugOut((DEB_USER5, "INITIALIZING keep-awake count to 0\n"));
  847. if (!TlsSetValue(g_WakeCountSlot, 0))
  848. {
  849. ERR_OUT("TlsSetValue", GetLastError());
  850. }
  851. }