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.

2065 lines
50 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 1997-1999 Microsoft Corporation
  4. //
  5. // File: jobmgr.cpp
  6. //
  7. // Contents: Job scheduler
  8. //
  9. // History:
  10. //
  11. //---------------------------------------------------------------------------
  12. #include "pch.cpp"
  13. #include <process.h>
  14. #include "server.h"
  15. #include "jobmgr.h"
  16. #include "debug.h"
  17. //------------------------------------------------------------
  18. //
  19. //
  20. CLASS_PRIVATE BOOL
  21. CWorkManager::SignalJobRunning(
  22. IN CWorkObject *ptr
  23. )
  24. /*++
  25. Abstract:
  26. Class private routine for work object to 'signal'
  27. work manger it has started processing.
  28. Parameter:
  29. ptr : Pointer to CWorkObject that is ready to run.
  30. Returns:
  31. TRUE/FALSE
  32. --*/
  33. {
  34. DWORD dwStatus = ERROR_SUCCESS;
  35. INPROCESSINGJOBLIST::iterator it;
  36. if(ptr != NULL)
  37. {
  38. m_InProcessingListLock.Lock();
  39. try {
  40. DBGPrintf(
  41. DBG_INFORMATION,
  42. DBG_FACILITY_WORKMGR,
  43. DBGLEVEL_FUNCTION_TRACE,
  44. _TEXT("WorkManager : SignalJobRunning() Job %p ...\n"),
  45. ptr
  46. );
  47. //
  48. // find our pointer in processing list
  49. //
  50. it = m_InProcessingList.find(ptr);
  51. if(it != m_InProcessingList.end())
  52. {
  53. // TODO - make processing thread handle a list.
  54. if((*it).second.m_hThread == NULL)
  55. {
  56. HANDLE hHandle;
  57. DWORD dwStatus;
  58. BOOL bSuccess;
  59. bSuccess = DuplicateHandle(
  60. GetCurrentProcess(),
  61. GetCurrentThread(),
  62. GetCurrentProcess(),
  63. &hHandle,
  64. DUPLICATE_SAME_ACCESS,
  65. FALSE,
  66. 0
  67. );
  68. if(bSuccess == FALSE)
  69. {
  70. //
  71. // non-critical error, if we fail, we won't be able to
  72. // cancel our rpc call.
  73. //
  74. SetLastError(dwStatus = GetLastError());
  75. DBGPrintf(
  76. DBG_INFORMATION,
  77. DBG_FACILITY_WORKMGR,
  78. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  79. _TEXT("WorkManager : SignalJobRunning() duplicate handle return %d...\n"),
  80. dwStatus
  81. );
  82. }
  83. else
  84. {
  85. //
  86. // set processing thread handle of job.
  87. //
  88. (*it).second.m_hThread = hHandle;
  89. }
  90. }
  91. }
  92. else
  93. {
  94. DBGPrintf(
  95. DBG_INFORMATION,
  96. DBG_FACILITY_WORKMGR,
  97. DBGLEVEL_FUNCTION_TRACE,
  98. _TEXT("WorkManager : SignalJobRunning can't find job %p in processing list...\n"),
  99. ptr
  100. );
  101. //
  102. // timing problem, job might be re-scheduled and actually execute before we have
  103. // time to remove from our in-processing list.
  104. //
  105. //TLSASSERT(FALSE);
  106. }
  107. }
  108. catch( SE_Exception e ) {
  109. SetLastError(dwStatus = e.getSeNumber());
  110. TLSASSERT(FALSE);
  111. }
  112. catch(...) {
  113. SetLastError(dwStatus = TLS_E_WORKMANAGER_INTERNAL);
  114. TLSASSERT(FALSE);
  115. }
  116. m_InProcessingListLock.UnLock();
  117. }
  118. else
  119. {
  120. SetLastError(dwStatus = ERROR_INVALID_DATA);
  121. }
  122. return dwStatus;
  123. }
  124. //----------------------------------------------------------------
  125. //
  126. CLASS_PRIVATE void
  127. CWorkManager::CancelInProcessingJob()
  128. /*++
  129. Abstract:
  130. Class private : cancel job currently in processing state,
  131. only invoked at the time of service shutdown.
  132. Parameter:
  133. None.
  134. Return:
  135. None.
  136. --*/
  137. {
  138. INPROCESSINGJOBLIST::iterator it;
  139. DBGPrintf(
  140. DBG_INFORMATION,
  141. DBG_FACILITY_WORKMGR,
  142. DBGLEVEL_FUNCTION_TRACE,
  143. _TEXT("WorkManager : CancelInProcessingJob...\n")
  144. );
  145. m_InProcessingListLock.Lock();
  146. try {
  147. for(it = m_InProcessingList.begin();
  148. it != m_InProcessingList.end();
  149. it++ )
  150. {
  151. if((*it).second.m_hThread != NULL)
  152. {
  153. // cancel everything and ignore error.
  154. (VOID)RpcCancelThread((*it).second.m_hThread);
  155. }
  156. }
  157. }
  158. catch( SE_Exception e ) {
  159. SetLastError(e.getSeNumber());
  160. }
  161. catch(...) {
  162. SetLastError(TLS_E_WORKMANAGER_INTERNAL);
  163. }
  164. m_InProcessingListLock.UnLock();
  165. return;
  166. }
  167. //------------------------------------------------------------
  168. //
  169. //
  170. CLASS_PRIVATE DWORD
  171. CWorkManager::AddJobToProcessingList(
  172. IN CWorkObject *ptr
  173. )
  174. /*++
  175. Abstract:
  176. Class private, move job from wait queue to in-process queue.
  177. Parameter:
  178. ptr : Pointer to job.
  179. Parameter:
  180. ERROR_SUCESS or error code.
  181. --*/
  182. {
  183. DWORD dwStatus = ERROR_SUCCESS;
  184. INPROCESSINGJOBLIST::iterator it;
  185. WorkMangerInProcessJob job;
  186. if(ptr == NULL)
  187. {
  188. SetLastError(dwStatus = ERROR_INVALID_DATA);
  189. }
  190. else
  191. {
  192. DBGPrintf(
  193. DBG_INFORMATION,
  194. DBG_FACILITY_WORKMGR,
  195. DBGLEVEL_FUNCTION_TRACE,
  196. _TEXT("WorkManager : Add Job <%s> to processing list...\n"),
  197. ptr->GetJobDescription()
  198. );
  199. m_InProcessingListLock.Lock();
  200. try {
  201. it = m_InProcessingList.find(ptr);
  202. if(it != m_InProcessingList.end())
  203. {
  204. // increase the reference counter.
  205. InterlockedIncrement(&((*it).second.m_refCounter));
  206. }
  207. else
  208. {
  209. job.m_refCounter = 1;
  210. job.m_hThread = NULL; // job not run yet.
  211. m_InProcessingList[ptr] = job;
  212. }
  213. ResetEvent(m_hJobInProcessing);
  214. }
  215. catch( SE_Exception e ) {
  216. SetLastError(dwStatus = e.getSeNumber());
  217. }
  218. catch(...) {
  219. SetLastError(dwStatus = TLS_E_WORKMANAGER_INTERNAL);
  220. }
  221. m_InProcessingListLock.UnLock();
  222. }
  223. return dwStatus;
  224. }
  225. //------------------------------------------------------------
  226. //
  227. //
  228. CLASS_PRIVATE DWORD
  229. CWorkManager::RemoveJobFromProcessingList(
  230. IN CWorkObject *ptr
  231. )
  232. /*++
  233. Abstract:
  234. Class private, remove a job from in-processing list.
  235. Parameter:
  236. ptr : Pointer to job to be removed from list.
  237. Returns:
  238. ERROR_SUCCESS or error code.
  239. --*/
  240. {
  241. DWORD dwStatus = ERROR_SUCCESS;
  242. INPROCESSINGJOBLIST::iterator it;
  243. if(ptr != NULL)
  244. {
  245. m_InProcessingListLock.Lock();
  246. try {
  247. DBGPrintf(
  248. DBG_INFORMATION,
  249. DBG_FACILITY_WORKMGR,
  250. DBGLEVEL_FUNCTION_TRACE,
  251. _TEXT("WorkManager : RemoveJobFromProcessingList Job %p from processing list...\n"),
  252. ptr
  253. );
  254. it = m_InProcessingList.find(ptr);
  255. if(it != m_InProcessingList.end())
  256. {
  257. // decrease the reference counter
  258. InterlockedDecrement(&((*it).second.m_refCounter));
  259. if((*it).second.m_refCounter <= 0)
  260. {
  261. // close thread handle.
  262. if((*it).second.m_hThread != NULL)
  263. {
  264. CloseHandle((*it).second.m_hThread);
  265. }
  266. m_InProcessingList.erase(it);
  267. }
  268. else
  269. {
  270. DBGPrintf(
  271. DBG_INFORMATION,
  272. DBG_FACILITY_WORKMGR,
  273. DBGLEVEL_FUNCTION_TRACE,
  274. _TEXT("WorkManager : RemoveJobFromProcessingList job %p reference counter = %d...\n"),
  275. ptr,
  276. (*it).second
  277. );
  278. }
  279. }
  280. else
  281. {
  282. DBGPrintf(
  283. DBG_INFORMATION,
  284. DBG_FACILITY_WORKMGR,
  285. DBGLEVEL_FUNCTION_TRACE,
  286. _TEXT("WorkManager : RemoveJobFromProcessingList can't find job %p in processing list...\n"),
  287. ptr
  288. );
  289. //
  290. // timing problem, job might be re-scheduled and actually execute before we have
  291. // time to remove from our in-processing list.
  292. //
  293. //TLSASSERT(FALSE);
  294. }
  295. if(m_InProcessingList.empty() == TRUE)
  296. {
  297. //
  298. // Inform Work Manager that no job is in processing.
  299. //
  300. SetEvent(m_hJobInProcessing);
  301. }
  302. }
  303. catch( SE_Exception e ) {
  304. SetLastError(dwStatus = e.getSeNumber());
  305. TLSASSERT(FALSE);
  306. }
  307. catch(...) {
  308. SetLastError(dwStatus = TLS_E_WORKMANAGER_INTERNAL);
  309. TLSASSERT(FALSE);
  310. }
  311. m_InProcessingListLock.UnLock();
  312. }
  313. else
  314. {
  315. SetLastError(dwStatus = ERROR_INVALID_DATA);
  316. }
  317. return dwStatus;
  318. }
  319. //------------------------------------------------------------
  320. //
  321. //
  322. CLASS_PRIVATE BOOL
  323. CWorkManager::WaitForObjectOrShutdown(
  324. IN HANDLE hHandle
  325. )
  326. /*++
  327. Abstract:
  328. Class private, Wait for a sync. handle or service shutdown
  329. event.
  330. Parameter:
  331. hHandle : handle to wait for,
  332. Returns:
  333. TRUE if sucessful, FALSE if service shutdown or error.
  334. --*/
  335. {
  336. HANDLE handles[] = {hHandle, m_hShutdown};
  337. DWORD dwStatus;
  338. dwStatus = WaitForMultipleObjects(
  339. sizeof(handles)/sizeof(handles[0]),
  340. handles,
  341. FALSE,
  342. INFINITE
  343. );
  344. return (dwStatus == WAIT_OBJECT_0);
  345. }
  346. //------------------------------------------------------------
  347. //
  348. //
  349. CLASS_PRIVATE DWORD
  350. CWorkManager::RunJob(
  351. IN CWorkObject* ptr,
  352. IN BOOL bImmediate
  353. )
  354. /*++
  355. Abstract:
  356. Process a job object via QueueUserWorkItem() Win32 API subject
  357. to our max. concurrent job limitation.
  358. Parameter:
  359. ptr : Pointer to CWorkObject.
  360. bImmediate : TRUE if job must be process immediately,
  361. FALSE otherwise.
  362. Returns:
  363. ERROR_SUCCESS or Error code.
  364. --*/
  365. {
  366. BOOL bSuccess;
  367. DWORD dwStatus = ERROR_SUCCESS;
  368. if(ptr != NULL)
  369. {
  370. DBGPrintf(
  371. DBG_INFORMATION,
  372. DBG_FACILITY_WORKMGR,
  373. DBGLEVEL_FUNCTION_TRACE,
  374. _TEXT("WorkManager : RunJob <%s>...\n"),
  375. ptr->GetJobDescription()
  376. );
  377. //
  378. // Wait if we exceed max. concurrent job
  379. //
  380. bSuccess = (bImmediate) ? bImmediate : m_hMaxJobLock.AcquireEx(m_hShutdown);
  381. if(bSuccess == TRUE)
  382. {
  383. DWORD dwFlag;
  384. DWORD dwJobRunningAttribute;
  385. dwJobRunningAttribute = ptr->GetJobRunningAttribute();
  386. dwFlag = TranslateJobRunningAttributeToThreadPoolFlag(
  387. dwJobRunningAttribute
  388. );
  389. dwStatus = AddJobToProcessingList(ptr);
  390. if(dwStatus == ERROR_SUCCESS)
  391. {
  392. DBGPrintf(
  393. DBG_INFORMATION,
  394. DBG_FACILITY_WORKMGR,
  395. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  396. _TEXT("RunJob() : queuing user work item %p...\n"),
  397. ptr
  398. );
  399. // need immediate attention.
  400. bSuccess = QueueUserWorkItem(
  401. CWorkManager::ExecuteWorkObject,
  402. ptr,
  403. dwFlag
  404. );
  405. if(bSuccess == FALSE)
  406. {
  407. dwStatus = GetLastError();
  408. DBGPrintf(
  409. DBG_ERROR,
  410. DBG_FACILITY_WORKMGR,
  411. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  412. _TEXT("RunJob() : queuing user work item %p failed with 0x%08x...\n"),
  413. ptr,
  414. dwStatus
  415. );
  416. //TLSASSERT(dwStatus == ERROR_SUCCESS);
  417. dwStatus = RemoveJobFromProcessingList(ptr);
  418. }
  419. }
  420. else
  421. {
  422. bSuccess = FALSE;
  423. }
  424. if(bSuccess == FALSE)
  425. {
  426. dwStatus = GetLastError();
  427. //TLSASSERT(FALSE);
  428. }
  429. //
  430. // release max. concurrent job lock
  431. //
  432. if(bImmediate == FALSE)
  433. {
  434. m_hMaxJobLock.Release();
  435. }
  436. }
  437. else
  438. {
  439. dwStatus = TLS_I_WORKMANAGER_SHUTDOWN;
  440. }
  441. }
  442. else
  443. {
  444. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  445. }
  446. return dwStatus;
  447. }
  448. //------------------------------------------------------------
  449. //
  450. //
  451. CLASS_PRIVATE DWORD
  452. CWorkManager::ProcessScheduledJob()
  453. /*++
  454. Abstract:
  455. Class private, process a scheduled job.
  456. Parameter:
  457. None.
  458. Return:
  459. ERROR_SUCCESS or error code.
  460. --*/
  461. {
  462. DWORD dwStatus = ERROR_SUCCESS;
  463. BOOL bSuccess = TRUE;
  464. DBGPrintf(
  465. DBG_INFORMATION,
  466. DBG_FACILITY_WORKMGR,
  467. DBGLEVEL_FUNCTION_TRACE,
  468. _TEXT("CWorkManager::ProcessScheduledJob(), %d %d\n"),
  469. GetNumberJobInStorageQueue(),
  470. GetNumberJobInMemoryQueue()
  471. );
  472. if(GetNumberJobInStorageQueue() != 0 && IsShuttingDown() == FALSE)
  473. {
  474. //
  475. // Could have use work item to process both
  476. // queue but this uses one extra handle, and
  477. // work manager thread will just doing nothing
  478. //
  479. ResetEvent(m_hInStorageWait);
  480. //
  481. // Queue a user work item to thread pool to process
  482. // in storage job
  483. //
  484. bSuccess = QueueUserWorkItem(
  485. CWorkManager::ProcessInStorageScheduledJob,
  486. this,
  487. WT_EXECUTELONGFUNCTION
  488. );
  489. if(bSuccess == FALSE)
  490. {
  491. dwStatus = GetLastError();
  492. DBGPrintf(
  493. DBG_ERROR,
  494. DBG_FACILITY_WORKMGR,
  495. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  496. _TEXT("CWorkManager::ProcessScheduledJob() queue user work iterm returns 0x%08x\n"),
  497. dwStatus
  498. );
  499. TLSASSERT(dwStatus == ERROR_SUCCESS);
  500. }
  501. }
  502. if(bSuccess == TRUE)
  503. {
  504. dwStatus = ProcessInMemoryScheduledJob(this);
  505. if(WaitForObjectOrShutdown(m_hInStorageWait) == FALSE)
  506. {
  507. dwStatus = TLS_I_WORKMANAGER_SHUTDOWN;
  508. }
  509. }
  510. return dwStatus;
  511. }
  512. //------------------------------------------------------------
  513. //
  514. //
  515. CLASS_PRIVATE CLASS_STATIC DWORD WINAPI
  516. CWorkManager::ProcessInMemoryScheduledJob(
  517. IN PVOID pContext
  518. )
  519. /*++
  520. Abstract:
  521. Static class private, process in-memory scheduled jobs.
  522. WorkManagerThread kick off two threads, one to process
  523. in-memory job and the other to process persistent job.
  524. Parameter:
  525. pContext : Pointer to work manager object.
  526. Return:
  527. ERROR_SUCCESS or error code.
  528. --*/
  529. {
  530. DWORD ulCurrentTime;
  531. DWORD dwJobTime;
  532. CWorkObject* pInMemoryWorkObject = NULL;
  533. BOOL bSuccess = TRUE;
  534. BOOL dwStatus = ERROR_SUCCESS;
  535. CWorkManager* pWkMgr = (CWorkManager *)pContext;
  536. DBGPrintf(
  537. DBG_INFORMATION,
  538. DBG_FACILITY_WORKMGR,
  539. DBGLEVEL_FUNCTION_TRACE,
  540. _TEXT("CWorkManager::ProcessInMemoryScheduledJob()\n")
  541. );
  542. if(pWkMgr == NULL)
  543. {
  544. SetLastError(ERROR_INVALID_PARAMETER);
  545. TLSASSERT(pWkMgr != NULL);
  546. return ERROR_INVALID_PARAMETER;
  547. }
  548. do {
  549. if(pWkMgr->IsShuttingDown() == TRUE)
  550. {
  551. dwStatus = TLS_I_WORKMANAGER_SHUTDOWN;
  552. break;
  553. }
  554. ulCurrentTime = time(NULL);
  555. dwJobTime = ulCurrentTime;
  556. pInMemoryWorkObject = pWkMgr->GetNextJobInMemoryQueue(&dwJobTime);
  557. if(pInMemoryWorkObject != NULL)
  558. {
  559. // TLSASSERT(dwJobTime <= ulCurrentTime);
  560. if(dwJobTime <= ulCurrentTime)
  561. {
  562. dwStatus = pWkMgr->RunJob(
  563. pInMemoryWorkObject,
  564. FALSE
  565. );
  566. if(dwStatus != ERROR_SUCCESS)
  567. {
  568. //
  569. // consider to re-schedule job again.
  570. //
  571. pInMemoryWorkObject->EndJob();
  572. if(pInMemoryWorkObject->CanBeDelete() == TRUE)
  573. {
  574. pInMemoryWorkObject->SelfDestruct();
  575. }
  576. }
  577. }
  578. else
  579. {
  580. //
  581. // Very expansive operation, GetNextJobInMemoryQueue() must be
  582. // wrong.
  583. //
  584. dwStatus = pWkMgr->AddJobIntoMemoryQueue(
  585. dwJobTime,
  586. pInMemoryWorkObject
  587. );
  588. if(dwStatus != ERROR_SUCCESS)
  589. {
  590. //
  591. // delete the job
  592. //
  593. pInMemoryWorkObject->EndJob();
  594. if(pInMemoryWorkObject->CanBeDelete() == TRUE)
  595. {
  596. pInMemoryWorkObject->SelfDestruct();
  597. }
  598. }
  599. }
  600. }
  601. } while(dwStatus == ERROR_SUCCESS && (pInMemoryWorkObject != NULL && dwJobTime <= ulCurrentTime));
  602. return dwStatus;
  603. }
  604. //------------------------------------------------------------
  605. //
  606. //
  607. CLASS_PRIVATE CLASS_STATIC DWORD WINAPI
  608. CWorkManager::ProcessInStorageScheduledJob(
  609. IN PVOID pContext
  610. )
  611. /*++
  612. Abstract:
  613. Static class private, process scheduled persistent jobs.
  614. WorkManagerThread kick off two threads, one to process
  615. in-memory job and the other to process persistent job.
  616. Parameter:
  617. pContext : Pointer to work manager object.
  618. Return:
  619. ERROR_SUCCESS or error code.
  620. --*/
  621. {
  622. DWORD ulCurrentTime = 0;
  623. DWORD dwJobScheduledTime = 0;
  624. CWorkObject* pInStorageWorkObject = NULL;
  625. DWORD dwStatus = ERROR_SUCCESS;
  626. BOOL bSuccess = TRUE;
  627. CWorkManager* pWkMgr = (CWorkManager *)pContext;
  628. DBGPrintf(
  629. DBG_INFORMATION,
  630. DBG_FACILITY_WORKMGR,
  631. DBGLEVEL_FUNCTION_TRACE,
  632. _TEXT("CWorkManager::ProcessInStorageScheduledJob()\n")
  633. );
  634. if(pWkMgr == NULL)
  635. {
  636. TLSASSERT(pWkMgr != NULL);
  637. SetLastError(ERROR_INVALID_PARAMETER);
  638. return ERROR_INVALID_PARAMETER;
  639. }
  640. TLSASSERT(pWkMgr->m_pPersistentWorkStorage != NULL);
  641. if(pWkMgr->m_pPersistentWorkStorage->GetNumJobs() > 0)
  642. {
  643. do
  644. {
  645. if(pWkMgr->IsShuttingDown() == TRUE)
  646. {
  647. dwStatus = TLS_I_WORKMANAGER_SHUTDOWN;
  648. break;
  649. }
  650. ulCurrentTime = time(NULL);
  651. pInStorageWorkObject = pWkMgr->m_pPersistentWorkStorage->GetNextJob(&dwJobScheduledTime);
  652. if(pInStorageWorkObject == NULL)
  653. {
  654. //
  655. // Something wrong in persistent storage???
  656. //
  657. DBGPrintf(
  658. DBG_WARNING,
  659. DBG_FACILITY_WORKMGR,
  660. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  661. _TEXT("CWorkManager::ProcessInStorageScheduledJob() : Persistent work storage return NULL job\n")
  662. );
  663. break;
  664. }
  665. else if(dwJobScheduledTime > ulCurrentTime)
  666. {
  667. DBGPrintf(
  668. DBG_WARNING,
  669. DBG_FACILITY_WORKMGR,
  670. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  671. _TEXT("CWorkManager::ProcessInStorageScheduledJob() : return job back to persistent storage\n")
  672. );
  673. pWkMgr->m_pPersistentWorkStorage->EndProcessingJob(
  674. ENDPROCESSINGJOB_RETURN,
  675. dwJobScheduledTime,
  676. pInStorageWorkObject
  677. );
  678. }
  679. else
  680. {
  681. pInStorageWorkObject->SetScheduledTime(dwJobScheduledTime);
  682. pWkMgr->m_pPersistentWorkStorage->BeginProcessingJob(pInStorageWorkObject);
  683. dwStatus = pWkMgr->RunJob(
  684. pInStorageWorkObject,
  685. FALSE
  686. );
  687. if(dwStatus != ERROR_SUCCESS)
  688. {
  689. DBGPrintf(
  690. DBG_WARNING,
  691. DBG_FACILITY_WORKMGR,
  692. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  693. _TEXT("CWorkManager::ProcessInStorageScheduledJob() : unable to queue job, return job back ") \
  694. _TEXT("to persistent storage\n")
  695. );
  696. pWkMgr->m_pPersistentWorkStorage->EndProcessingJob(
  697. ENDPROCESSINGJOB_RETURN,
  698. pInStorageWorkObject->GetScheduledTime(),
  699. pInStorageWorkObject
  700. );
  701. }
  702. }
  703. } while(dwStatus == ERROR_SUCCESS && ulCurrentTime >= dwJobScheduledTime);
  704. }
  705. //
  706. // Signal we are done
  707. //
  708. SetEvent(pWkMgr->m_hInStorageWait);
  709. return dwStatus;
  710. }
  711. //------------------------------------------------------------
  712. //
  713. //
  714. CLASS_PRIVATE CLASS_STATIC
  715. unsigned int __stdcall
  716. CWorkManager::WorkManagerThread(
  717. IN PVOID pContext
  718. )
  719. /*++
  720. Abstract:
  721. Static class private, this is the work manager thread to handle
  722. job scheduling and process scheduled job. WorkManagerThread()
  723. will not terminate until m_hShutdown event is signal.
  724. Parameter:
  725. pContext : Pointer to work manager object.
  726. Returns:
  727. ERROR_SUCCESS
  728. --*/
  729. {
  730. DWORD dwTimeToNextJob = INFINITE;
  731. CWorkManager* pWkMgr = (CWorkManager *)pContext;
  732. DWORD dwHandleFlag;
  733. TLSASSERT(pWkMgr != NULL);
  734. TLSASSERT(GetHandleInformation(pWkMgr->m_hNewJobArrive, &dwHandleFlag) == TRUE);
  735. TLSASSERT(GetHandleInformation(pWkMgr->m_hShutdown, &dwHandleFlag) == TRUE);
  736. HANDLE m_hWaitHandles[] = {pWkMgr->m_hShutdown, pWkMgr->m_hNewJobArrive};
  737. DWORD dwWaitStatus = WAIT_TIMEOUT;
  738. DWORD dwStatus = ERROR_SUCCESS;
  739. //
  740. // Get the time to next job
  741. //
  742. while(dwWaitStatus != WAIT_OBJECT_0 && dwStatus == ERROR_SUCCESS)
  743. {
  744. DBGPrintf(
  745. DBG_INFORMATION,
  746. DBG_FACILITY_WORKMGR,
  747. DBGLEVEL_FUNCTION_TRACE,
  748. _TEXT("CWorkManager::WorkManagerThread() : Time to next job %d\n"),
  749. dwTimeToNextJob
  750. );
  751. dwWaitStatus = WaitForMultipleObjectsEx(
  752. sizeof(m_hWaitHandles) / sizeof(m_hWaitHandles[0]),
  753. m_hWaitHandles,
  754. FALSE,
  755. dwTimeToNextJob * 1000,
  756. TRUE // we might need this thread to do some work
  757. );
  758. switch( dwWaitStatus )
  759. {
  760. case WAIT_OBJECT_0:
  761. dwStatus = ERROR_SUCCESS;
  762. DBGPrintf(
  763. DBG_INFORMATION,
  764. DBG_FACILITY_WORKMGR,
  765. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  766. _TEXT("CWorkManager::WorkManagerThread() : shutdown ...\n")
  767. );
  768. break;
  769. case WAIT_OBJECT_0 + 1:
  770. // still a possibility that we might not catch a new job
  771. ResetEvent(pWkMgr->m_hNewJobArrive);
  772. // New Job arrived
  773. dwTimeToNextJob = pWkMgr->GetTimeToNextJob();
  774. break;
  775. case WAIT_TIMEOUT:
  776. // Time to process job.
  777. dwStatus = pWkMgr->ProcessScheduledJob();
  778. dwTimeToNextJob = pWkMgr->GetTimeToNextJob();
  779. break;
  780. default:
  781. DBGPrintf(
  782. DBG_ERROR,
  783. DBG_FACILITY_WORKMGR,
  784. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  785. _TEXT("CWorkManager::WorkManagerThread() : unexpected return %d\n"),
  786. dwStatus
  787. );
  788. dwStatus = TLS_E_WORKMANAGER_INTERNAL;
  789. TLSASSERT(FALSE);
  790. }
  791. }
  792. if(dwStatus != ERROR_SUCCESS && dwStatus != TLS_I_WORKMANAGER_SHUTDOWN)
  793. {
  794. DBGPrintf(
  795. DBG_ERROR,
  796. DBG_FACILITY_WORKMGR,
  797. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  798. _TEXT("CWorkManager::WorkManagerThread() : unexpected return %d, generate console event\n"),
  799. dwStatus
  800. );
  801. // immediately shut down server
  802. GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
  803. }
  804. _endthreadex(dwStatus);
  805. return dwStatus;
  806. }
  807. //----------------------------------------------------------------
  808. //
  809. //
  810. CLASS_PRIVATE CLASS_STATIC
  811. DWORD WINAPI
  812. CWorkManager::ExecuteWorkObject(
  813. IN PVOID pContext
  814. )
  815. /*++
  816. Abstract:
  817. Static class private, execute a work object.
  818. Parameter:
  819. pContext : Pointer to work object to be process.
  820. Returns:
  821. ERROR_SUCCESS or error code.
  822. --*/
  823. {
  824. DWORD dwStatus = ERROR_SUCCESS;
  825. CWorkObject* pWorkObject = (CWorkObject *)pContext;
  826. DWORD dwJobRescheduleTime;
  827. BOOL bStorageJobCompleted;
  828. CWorkManager* pWkMgr = NULL;
  829. BOOL bPersistentJob = FALSE;
  830. if(pContext == NULL)
  831. {
  832. TLSASSERT(FALSE);
  833. dwStatus = ERROR_INVALID_PARAMETER;
  834. return dwStatus;
  835. }
  836. DBGPrintf(
  837. DBG_INFORMATION,
  838. DBG_FACILITY_WORKMGR,
  839. DBGLEVEL_FUNCTION_TRACE,
  840. _TEXT("CWorkManager::ExecuteWorkObject() : executing %p <%s>\n"),
  841. pWorkObject,
  842. pWorkObject->GetJobDescription()
  843. );
  844. _se_translator_function old_trans_se_func = NULL;
  845. old_trans_se_func = _set_se_translator( trans_se_func );
  846. //
  847. // Set RPC cancel timeout, thread dependent.
  848. (VOID)RpcMgmtSetCancelTimeout(DEFAULT_RPCCANCEL_TIMEOUT);
  849. bPersistentJob = pWorkObject->IsWorkPersistent();
  850. try {
  851. pWkMgr = pWorkObject->GetWorkManager();
  852. if(pWkMgr != NULL)
  853. {
  854. pWkMgr->SignalJobRunning(pWorkObject); // tell work manager that we are running
  855. pWorkObject->ExecuteWorkObject();
  856. if(bPersistentJob == TRUE)
  857. {
  858. //
  859. // Persistent work object, let work storage handle
  860. // its re-scheduling
  861. //
  862. bStorageJobCompleted = pWorkObject->IsJobCompleted();
  863. pWorkObject->GetWorkManager()->m_pPersistentWorkStorage->EndProcessingJob(
  864. ENDPROCESSINGJOB_SUCCESS,
  865. pWorkObject->GetScheduledTime(),
  866. pWorkObject
  867. );
  868. if(bStorageJobCompleted == FALSE)
  869. {
  870. //
  871. // This job might be re-scheduled
  872. // before our work manager thread wakes up,
  873. // so signal job is ready
  874. //
  875. pWkMgr->SignalJobArrive();
  876. }
  877. }
  878. else
  879. {
  880. //
  881. // Reschedule job if necessary
  882. //
  883. dwJobRescheduleTime = pWorkObject->GetSuggestedScheduledTime();
  884. if(dwJobRescheduleTime != INFINITE)
  885. {
  886. dwStatus = pWorkObject->ScheduleJob(dwJobRescheduleTime);
  887. }
  888. if(dwJobRescheduleTime == INFINITE || dwStatus != ERROR_SUCCESS)
  889. {
  890. //
  891. // if can't schedule job again, go ahead and delete it.
  892. //
  893. pWorkObject->EndJob();
  894. if(pWorkObject->CanBeDelete() == TRUE)
  895. {
  896. pWorkObject->SelfDestruct();
  897. }
  898. }
  899. }
  900. }
  901. }
  902. catch( SE_Exception e )
  903. {
  904. DBGPrintf(
  905. DBG_ERROR,
  906. DBG_FACILITY_WORKMGR,
  907. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  908. _TEXT("CWorkManager::ExecuteWorkObject() : Job %p has cause exception %d\n"),
  909. pWorkObject,
  910. e.getSeNumber()
  911. );
  912. dwStatus = e.getSeNumber();
  913. if(pWkMgr != NULL && bPersistentJob == TRUE)
  914. {
  915. pWkMgr->m_pPersistentWorkStorage->EndProcessingJob(
  916. ENDPROCESSINGJOB_ERROR,
  917. 0,
  918. pWorkObject
  919. );
  920. }
  921. }
  922. catch(...)
  923. {
  924. DBGPrintf(
  925. DBG_ERROR,
  926. DBG_FACILITY_WORKMGR,
  927. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  928. _TEXT("CWorkManager::ExecuteWorkObject() : Job %p has cause unknown exception\n"),
  929. pWorkObject
  930. );
  931. if(pWkMgr != NULL && bPersistentJob == TRUE)
  932. {
  933. pWkMgr->m_pPersistentWorkStorage->EndProcessingJob(
  934. ENDPROCESSINGJOB_ERROR,
  935. 0,
  936. pWorkObject
  937. );
  938. }
  939. }
  940. try {
  941. if(pWkMgr)
  942. {
  943. // Delete this job from in-processing list.
  944. pWkMgr->EndProcessingScheduledJob(pWorkObject);
  945. }
  946. }
  947. catch(...) {
  948. }
  949. //
  950. // Reset SE translator
  951. //
  952. _set_se_translator(old_trans_se_func);
  953. return dwStatus;
  954. }
  955. //----------------------------------------------------------------
  956. //
  957. //
  958. CWorkManager::CWorkManager() :
  959. m_hWorkMgrThread(NULL),
  960. m_hNewJobArrive(NULL),
  961. m_hShutdown(NULL),
  962. m_hInStorageWait(NULL),
  963. m_hJobInProcessing(NULL),
  964. m_dwNextInMemoryJobTime(WORKMANAGER_WAIT_FOREVER),
  965. m_dwNextInStorageJobTime(WORKMANAGER_WAIT_FOREVER),
  966. m_dwMaxCurrentJob(DEFAULT_NUM_CONCURRENTJOB),
  967. m_dwDefaultInterval(DEFAULT_WORK_INTERVAL)
  968. {
  969. }
  970. //----------------------------------------------------------------
  971. //
  972. CWorkManager::~CWorkManager()
  973. {
  974. Shutdown();
  975. if(m_hNewJobArrive != NULL)
  976. {
  977. CloseHandle(m_hNewJobArrive);
  978. }
  979. if(m_hWorkMgrThread != NULL)
  980. {
  981. CloseHandle(m_hWorkMgrThread);
  982. }
  983. if(m_hShutdown != NULL)
  984. {
  985. CloseHandle(m_hShutdown);
  986. }
  987. if(m_hInStorageWait != NULL)
  988. {
  989. CloseHandle(m_hInStorageWait);
  990. }
  991. if(m_hJobInProcessing != NULL)
  992. {
  993. CloseHandle(m_hJobInProcessing);
  994. }
  995. }
  996. //----------------------------------------------------------------
  997. //
  998. DWORD
  999. CWorkManager::Startup(
  1000. IN CWorkStorage* pPersistentWorkStorage,
  1001. IN DWORD dwWorkInterval, // DEFAULT_WORK_INTERVAL
  1002. IN DWORD dwNumConcurrentJob // DEFAULT_NUM_CONCURRENTJOB
  1003. )
  1004. /*++
  1005. Abstract:
  1006. Initialize work manager
  1007. Parameters:
  1008. pPersistentWorkStorage : A C++ object that derived from CPersistentWorkStorage class
  1009. dwWorkInterval : Default schedule job interval
  1010. dwNumConcurrentJob : Max. number of concurrent job to be fired at the same time
  1011. Return:
  1012. ERROR_SUCCESS or Erro Code.
  1013. --*/
  1014. {
  1015. DWORD index;
  1016. DWORD dwStatus = ERROR_SUCCESS;
  1017. unsigned dump;
  1018. BOOL bSuccess;
  1019. unsigned threadid;
  1020. #ifdef __TEST_WORKMGR__
  1021. _set_new_handler(handle_new_failed);
  1022. #endif
  1023. if(dwNumConcurrentJob == 0 || dwWorkInterval == 0 || pPersistentWorkStorage == NULL)
  1024. {
  1025. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1026. goto cleanup;
  1027. }
  1028. if(m_hMaxJobLock.IsGood() == FALSE)
  1029. {
  1030. if(m_hMaxJobLock.Init(dwNumConcurrentJob, dwNumConcurrentJob) == FALSE)
  1031. {
  1032. //
  1033. // out of resource
  1034. //
  1035. dwStatus = GetLastError();
  1036. goto cleanup;
  1037. }
  1038. }
  1039. m_dwDefaultInterval = dwWorkInterval;
  1040. m_dwMaxCurrentJob = dwNumConcurrentJob;
  1041. m_pPersistentWorkStorage = pPersistentWorkStorage;
  1042. if(m_hJobInProcessing == NULL)
  1043. {
  1044. //
  1045. // initial state is signal, no job in processing
  1046. //
  1047. m_hJobInProcessing = CreateEvent(
  1048. NULL,
  1049. TRUE,
  1050. TRUE,
  1051. NULL
  1052. );
  1053. if(m_hJobInProcessing == NULL)
  1054. {
  1055. dwStatus = GetLastError();
  1056. goto cleanup;
  1057. }
  1058. }
  1059. if(m_hShutdown == NULL)
  1060. {
  1061. //
  1062. // Create a handle for signaling shutdown
  1063. //
  1064. m_hShutdown = CreateEvent(
  1065. NULL,
  1066. TRUE,
  1067. FALSE,
  1068. NULL
  1069. );
  1070. if(m_hShutdown == NULL)
  1071. {
  1072. dwStatus = GetLastError();
  1073. goto cleanup;
  1074. }
  1075. }
  1076. if(m_hNewJobArrive == NULL)
  1077. {
  1078. //
  1079. // initial state is signal so work manager thread can
  1080. // update wait time
  1081. //
  1082. m_hNewJobArrive = CreateEvent(
  1083. NULL,
  1084. TRUE,
  1085. TRUE,
  1086. NULL
  1087. );
  1088. if(m_hNewJobArrive == NULL)
  1089. {
  1090. dwStatus = GetLastError();
  1091. goto cleanup;
  1092. }
  1093. }
  1094. if(m_hInStorageWait == NULL)
  1095. {
  1096. m_hInStorageWait = CreateEvent(
  1097. NULL,
  1098. TRUE,
  1099. TRUE, // signal state
  1100. NULL
  1101. );
  1102. if(m_hInStorageWait == NULL)
  1103. {
  1104. dwStatus = GetLastError();
  1105. goto cleanup;
  1106. }
  1107. }
  1108. //
  1109. // Startup Work Storage first.
  1110. //
  1111. if(m_pPersistentWorkStorage->Startup(this) == FALSE)
  1112. {
  1113. DBGPrintf(
  1114. DBG_ERROR,
  1115. DBG_FACILITY_WORKMGR,
  1116. DBGLEVEL_FUNCTION_DETAILSIMPLE,
  1117. _TEXT("CWorkManager::Startup() : Persistent storage has failed to startup - 0x%08x\n"),
  1118. GetLastError()
  1119. );
  1120. dwStatus = TLS_E_WORKMANAGER_PERSISTENJOB;
  1121. goto cleanup;
  1122. }
  1123. //
  1124. // Get time to next persistent job.
  1125. //
  1126. if(UpdateTimeToNextPersistentJob() == FALSE)
  1127. {
  1128. dwStatus = TLS_E_WORKMANAGER_PERSISTENJOB;
  1129. goto cleanup;
  1130. }
  1131. if(m_hWorkMgrThread == NULL)
  1132. {
  1133. //
  1134. // Create work manager thread, suspended first
  1135. //
  1136. m_hWorkMgrThread = (HANDLE)_beginthreadex(
  1137. NULL,
  1138. 0,
  1139. CWorkManager::WorkManagerThread,
  1140. this,
  1141. 0,
  1142. &threadid
  1143. );
  1144. if(m_hWorkMgrThread == NULL)
  1145. {
  1146. dwStatus = GetLastError();
  1147. goto cleanup;
  1148. }
  1149. }
  1150. cleanup:
  1151. return dwStatus;
  1152. }
  1153. //----------------------------------------------------------------
  1154. void
  1155. CWorkManager::Shutdown()
  1156. /*++
  1157. Abstract:
  1158. Shutdown work manager.
  1159. Parameter:
  1160. None.
  1161. Return:
  1162. None.
  1163. --*/
  1164. {
  1165. HANDLE handles[] = {m_hInStorageWait, m_hJobInProcessing};
  1166. DWORD dwStatus;
  1167. //
  1168. // Signal we are shuting down
  1169. //
  1170. if(m_hShutdown != NULL)
  1171. {
  1172. SetEvent(m_hShutdown);
  1173. }
  1174. //
  1175. // Wait for dispatch thread to terminate so no job can be
  1176. // dispatched.
  1177. //
  1178. if(m_hWorkMgrThread != NULL)
  1179. {
  1180. dwStatus = WaitForSingleObject(
  1181. m_hWorkMgrThread,
  1182. INFINITE
  1183. );
  1184. TLSASSERT(dwStatus != WAIT_FAILED);
  1185. CloseHandle(m_hWorkMgrThread);
  1186. m_hWorkMgrThread = NULL;
  1187. }
  1188. //
  1189. // Cancel all in progress job
  1190. //
  1191. CancelInProcessingJob();
  1192. //
  1193. // Inform all existing job to shutdown.
  1194. //
  1195. DeleteAllJobsInMemoryQueue();
  1196. //
  1197. // Wait for all processing job to terminate
  1198. //
  1199. if(m_hInStorageWait != NULL && m_hJobInProcessing != NULL)
  1200. {
  1201. dwStatus = WaitForMultipleObjects(
  1202. sizeof(handles)/sizeof(handles[0]),
  1203. handles,
  1204. TRUE,
  1205. INFINITE
  1206. );
  1207. TLSASSERT(dwStatus != WAIT_FAILED);
  1208. CloseHandle(m_hInStorageWait);
  1209. m_hInStorageWait = NULL;
  1210. CloseHandle(m_hJobInProcessing);
  1211. m_hJobInProcessing = NULL;
  1212. }
  1213. if(m_pPersistentWorkStorage != NULL)
  1214. {
  1215. //
  1216. // Signal we are shutting down, no job is in
  1217. // processing and we are not taking any
  1218. // new job
  1219. //
  1220. m_pPersistentWorkStorage->Shutdown();
  1221. m_pPersistentWorkStorage = NULL;
  1222. }
  1223. TLSASSERT( GetNumberJobInProcessing() == 0 );
  1224. // TLSASSERT( GetNumberJobInMemoryQueue() == 0 );
  1225. if(m_hNewJobArrive != NULL)
  1226. {
  1227. CloseHandle(m_hNewJobArrive);
  1228. m_hNewJobArrive = NULL;
  1229. }
  1230. if(m_hWorkMgrThread != NULL)
  1231. {
  1232. CloseHandle(m_hWorkMgrThread);
  1233. m_hWorkMgrThread = NULL;
  1234. }
  1235. if(m_hShutdown != NULL)
  1236. {
  1237. CloseHandle(m_hShutdown);
  1238. m_hShutdown = NULL;
  1239. }
  1240. if(m_hInStorageWait != NULL)
  1241. {
  1242. CloseHandle(m_hInStorageWait);
  1243. m_hInStorageWait = NULL;
  1244. }
  1245. if(m_hJobInProcessing != NULL)
  1246. {
  1247. CloseHandle(m_hJobInProcessing);
  1248. m_hJobInProcessing = NULL;
  1249. }
  1250. return;
  1251. }
  1252. //----------------------------------------------------------------
  1253. CLASS_PRIVATE DWORD
  1254. CWorkManager::GetTimeToNextJob()
  1255. /*++
  1256. Abstract:
  1257. Class private, return time to next scheduled job.
  1258. Parameter:
  1259. None.
  1260. Return:
  1261. Time to next job in second.
  1262. --*/
  1263. {
  1264. DWORD dwNextJobTime = WORKMANAGER_WAIT_FOREVER;
  1265. DWORD dwNumPersistentJob = GetNumberJobInStorageQueue();
  1266. DWORD dwNumInMemoryJob = GetNumberJobInMemoryQueue();
  1267. DWORD dwCurrentTime = time(NULL);
  1268. if( dwNumPersistentJob == 0 && dwNumInMemoryJob == 0 )
  1269. {
  1270. // DO NOTHING
  1271. // dwTimeToNextJob = WORKMANAGER_WAIT_FOREVER;
  1272. }
  1273. else
  1274. {
  1275. UpdateTimeToNextInMemoryJob();
  1276. UpdateTimeToNextPersistentJob();
  1277. dwNextJobTime = min((DWORD)m_dwNextInMemoryJobTime, (DWORD)m_dwNextInStorageJobTime);
  1278. if((DWORD)dwNextJobTime < (DWORD)dwCurrentTime)
  1279. {
  1280. dwNextJobTime = 0;
  1281. }
  1282. else
  1283. {
  1284. dwNextJobTime -= dwCurrentTime;
  1285. }
  1286. }
  1287. return dwNextJobTime;
  1288. }
  1289. //----------------------------------------------------------------
  1290. //
  1291. CLASS_PRIVATE CWorkObject*
  1292. CWorkManager::GetNextJobInMemoryQueue(
  1293. PDWORD pdwTime
  1294. )
  1295. /*++
  1296. Abstract:
  1297. Class private, return pointer to next scheduled
  1298. in memory job.
  1299. Parameter:
  1300. pdwTime : Pointer to DWORD to receive time to the
  1301. scheduled job.
  1302. Returns:
  1303. Pointer to CWorkObject.
  1304. Note:
  1305. Remove the job from queue if job is <= time.
  1306. --*/
  1307. {
  1308. SCHEDULEJOBMAP::iterator it;
  1309. DWORD dwWantedJobTime;
  1310. CWorkObject* ptr = NULL;
  1311. SetLastError(ERROR_SUCCESS);
  1312. if(pdwTime != NULL)
  1313. {
  1314. dwWantedJobTime = *pdwTime;
  1315. m_JobLock.Acquire(READER_LOCK);
  1316. it = m_Jobs.begin();
  1317. if(it != m_Jobs.end())
  1318. {
  1319. *pdwTime = (*it).first;
  1320. if(dwWantedJobTime >= *pdwTime)
  1321. {
  1322. ptr = (*it).second;
  1323. // remove job from queue
  1324. m_Jobs.erase(it);
  1325. }
  1326. }
  1327. m_JobLock.Release(READER_LOCK);
  1328. }
  1329. else
  1330. {
  1331. SetLastError(ERROR_INVALID_PARAMETER);
  1332. }
  1333. return ptr;
  1334. }
  1335. //----------------------------------------------------------------
  1336. //
  1337. CLASS_PRIVATE void
  1338. CWorkManager::DeleteAllJobsInMemoryQueue()
  1339. /*++
  1340. Abstract:
  1341. Class private, unconditionally delete all in-memory job.
  1342. Parameter:
  1343. None.
  1344. Return:
  1345. None.
  1346. --*/
  1347. {
  1348. m_JobLock.Acquire(WRITER_LOCK);
  1349. SCHEDULEJOBMAP::iterator it;
  1350. for(it = m_Jobs.begin(); it != m_Jobs.end(); it++)
  1351. {
  1352. try {
  1353. //
  1354. // let calling routine to delete it
  1355. //
  1356. (*it).second->EndJob();
  1357. if((*it).second->CanBeDelete() == TRUE)
  1358. {
  1359. (*it).second->SelfDestruct();
  1360. }
  1361. (*it).second = NULL;
  1362. }
  1363. catch(...) {
  1364. }
  1365. }
  1366. m_Jobs.erase(m_Jobs.begin(), m_Jobs.end());
  1367. m_JobLock.Release(WRITER_LOCK);
  1368. return;
  1369. }
  1370. //----------------------------------------------------------------
  1371. //
  1372. CLASS_PRIVATE BOOL
  1373. CWorkManager::RemoveJobFromInMemoryQueue(
  1374. IN DWORD ulTime,
  1375. IN CWorkObject* ptr
  1376. )
  1377. /*++
  1378. Abstract:
  1379. Class private, remove a scheduled job.
  1380. Parameters:
  1381. ulTime : Job scheduled time.
  1382. ptr : Pointer to Job to be deleted.
  1383. Returns:
  1384. TRUE/FALSE.
  1385. Note:
  1386. A job might be scheduled multiple time so we
  1387. need to pass in the time.
  1388. --*/
  1389. {
  1390. BOOL bSuccess = FALSE;
  1391. m_JobLock.Acquire(WRITER_LOCK);
  1392. SCHEDULEJOBMAP::iterator low = m_Jobs.lower_bound(ulTime);
  1393. SCHEDULEJOBMAP::iterator high = m_Jobs.upper_bound(ulTime);
  1394. for(;low != m_Jobs.end() && low != high; low++)
  1395. {
  1396. if( (*low).second == ptr )
  1397. {
  1398. //
  1399. // let calling routine to delete it
  1400. //
  1401. (*low).second = NULL;
  1402. m_Jobs.erase(low);
  1403. bSuccess = TRUE;
  1404. break;
  1405. }
  1406. }
  1407. if(bSuccess == FALSE)
  1408. {
  1409. SetLastError(ERROR_INVALID_DATA);
  1410. TLSASSERT(FALSE);
  1411. }
  1412. m_JobLock.Release(WRITER_LOCK);
  1413. return bSuccess;
  1414. }
  1415. //----------------------------------------------------------------
  1416. //
  1417. CLASS_PRIVATE DWORD
  1418. CWorkManager::AddJobIntoMemoryQueue(
  1419. IN DWORD dwTime, // suggested scheduled time
  1420. IN CWorkObject* pJob // Job to be scheduled
  1421. )
  1422. /*++
  1423. Abstract:
  1424. Class private, add a job into in-memory list.
  1425. Parameters:
  1426. dwTime : suggested scheduled time.
  1427. pJob : Pointer to job to be added.
  1428. Returns:
  1429. ERROR_SUCCESS or error code.
  1430. --*/
  1431. {
  1432. DWORD dwStatus = ERROR_SUCCESS;
  1433. BOOL bSuccess = FALSE;
  1434. DWORD dwJobScheduleTime = time(NULL) + dwTime;
  1435. if(IsShuttingDown() == TRUE)
  1436. {
  1437. dwStatus = TLS_I_WORKMANAGER_SHUTDOWN;
  1438. return dwStatus;
  1439. }
  1440. m_JobLock.Acquire(WRITER_LOCK);
  1441. try {
  1442. //
  1443. // insert a job into our queue
  1444. //
  1445. m_Jobs.insert( SCHEDULEJOBMAP::value_type( dwJobScheduleTime, pJob ) );
  1446. AddJobUpdateInMemoryJobWaitTimer(dwJobScheduleTime);
  1447. }
  1448. catch( SE_Exception e )
  1449. {
  1450. dwStatus = e.getSeNumber();
  1451. }
  1452. catch(...)
  1453. {
  1454. // need to reset to tlserver error code
  1455. dwStatus = TLS_E_WORKMANAGER_INTERNAL;
  1456. }
  1457. m_JobLock.Release(WRITER_LOCK);
  1458. return dwStatus;
  1459. }
  1460. //----------------------------------------------------------------
  1461. //
  1462. DWORD
  1463. CWorkManager::ScheduleJob(
  1464. IN DWORD ulTime, // suggested scheduled time
  1465. IN CWorkObject* pJob // Job to be scheduled
  1466. )
  1467. /*++
  1468. Abstract:
  1469. Schedule a job at time relative to current time
  1470. Parameters:
  1471. ulTime : suggested scheduled time.
  1472. pJob : Pointer to job to be scheduled
  1473. Returns:
  1474. ERROR_SUCCESS or error code.
  1475. --*/
  1476. {
  1477. BOOL bSuccess = TRUE;
  1478. DWORD dwStatus = ERROR_SUCCESS;
  1479. if(pJob == NULL)
  1480. {
  1481. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1482. goto cleanup;
  1483. }
  1484. if(IsShuttingDown() == TRUE)
  1485. {
  1486. SetLastError(dwStatus = TLS_I_WORKMANAGER_SHUTDOWN);
  1487. goto cleanup;
  1488. }
  1489. DBGPrintf(
  1490. DBG_INFORMATION,
  1491. DBG_FACILITY_WORKMGR,
  1492. DBGLEVEL_FUNCTION_TRACE,
  1493. _TEXT("CWorkManager::ScheduleJob() : schedule job <%s> to queue at time %d\n"),
  1494. pJob->GetJobDescription(),
  1495. ulTime
  1496. );
  1497. pJob->SetProcessingWorkManager(this);
  1498. if(ulTime == INFINITE && pJob->IsWorkPersistent() == FALSE)
  1499. {
  1500. //
  1501. // Only in-memory job can be executed at once.
  1502. //
  1503. dwStatus = RunJob(pJob, TRUE);
  1504. }
  1505. else
  1506. {
  1507. if(pJob->IsWorkPersistent() == TRUE)
  1508. {
  1509. if(m_pPersistentWorkStorage->AddJob(ulTime, pJob) == FALSE)
  1510. {
  1511. dwStatus = TLS_E_WORKMANAGER_PERSISTENJOB;
  1512. }
  1513. }
  1514. else
  1515. {
  1516. //
  1517. // insert a workobject into job queue, reason not to
  1518. // use RegisterWaitForSingleObject() or threadpool's timer
  1519. // is that we don't need to track handle nor wait for
  1520. // DeleteTimerXXX to finish
  1521. //
  1522. dwStatus = AddJobIntoMemoryQueue(
  1523. ulTime, // Memory queue is absolute time
  1524. pJob
  1525. );
  1526. }
  1527. if(dwStatus == ERROR_SUCCESS)
  1528. {
  1529. if(SignalJobArrive() == FALSE)
  1530. {
  1531. dwStatus = GetLastError();
  1532. TLSASSERT(FALSE);
  1533. }
  1534. }
  1535. }
  1536. cleanup:
  1537. return dwStatus;
  1538. }
  1539. ///////////////////////////////////////////////////////////////
  1540. //
  1541. // CWorkObject base class
  1542. //
  1543. CWorkObject::CWorkObject(
  1544. IN BOOL bDestructorDelete /* = FALSE */
  1545. ) :
  1546. m_dwLastRunStatus(ERROR_SUCCESS),
  1547. m_refCount(0),
  1548. m_pWkMgr(NULL),
  1549. m_bCanBeFree(bDestructorDelete)
  1550. {
  1551. }
  1552. //----------------------------------------------------------
  1553. DWORD
  1554. CWorkObject::Init(
  1555. IN BOOL bDestructorDelete /* = FALSE */
  1556. )
  1557. /*++
  1558. Abstract:
  1559. Initialize a work object.
  1560. Parameter:
  1561. bDestructorDelete : TRUE if destructor should delete the memory,
  1562. FALSE otherwise.
  1563. Returns:
  1564. ERROR_SUCCESS or error code.
  1565. Note:
  1566. if bDestructorDelete is FALSE, memory will not be free.
  1567. --*/
  1568. {
  1569. m_dwLastRunStatus = ERROR_SUCCESS;
  1570. m_refCount = 0;
  1571. m_bCanBeFree = bDestructorDelete;
  1572. return ERROR_SUCCESS;
  1573. }
  1574. //----------------------------------------------------------
  1575. CLASS_PRIVATE long
  1576. CWorkObject::GetReferenceCount()
  1577. /*++
  1578. Abstract:
  1579. Return reference count of work object.
  1580. Parameter:
  1581. None.
  1582. Return:
  1583. Reference count.
  1584. --*/
  1585. {
  1586. return m_refCount;
  1587. }
  1588. //----------------------------------------------------------
  1589. CLASS_PRIVATE void
  1590. CWorkObject::IncrementRefCount()
  1591. /*++
  1592. Abstract:
  1593. Increment object's reference counter.
  1594. Parameter:
  1595. None.
  1596. Return:
  1597. None.
  1598. --*/
  1599. {
  1600. InterlockedIncrement(&m_refCount);
  1601. }
  1602. //----------------------------------------------------------
  1603. CLASS_PRIVATE void
  1604. CWorkObject::DecrementRefCount()
  1605. /*++
  1606. Abstract:
  1607. Decrement object's reference counter.
  1608. Parameter:
  1609. None.
  1610. Return:
  1611. None.
  1612. --*/
  1613. {
  1614. InterlockedDecrement(&m_refCount);
  1615. }
  1616. //----------------------------------------------------------
  1617. CLASS_PRIVATE void
  1618. CWorkObject::ExecuteWorkObject()
  1619. /*++
  1620. Abstract:
  1621. Execute a work object. Work manager invoke work object's
  1622. ExecuteWorkObject so that base class can set its reference
  1623. counter.
  1624. Parameter:
  1625. None.
  1626. Return:
  1627. None.
  1628. --*/
  1629. {
  1630. if(IsValid() == TRUE)
  1631. {
  1632. IncrementRefCount();
  1633. m_dwLastRunStatus = Execute();
  1634. DecrementRefCount();
  1635. }
  1636. else
  1637. {
  1638. m_dwLastRunStatus = ERROR_INVALID_DATA;
  1639. TLSASSERT(FALSE);
  1640. }
  1641. }
  1642. //----------------------------------------------------------
  1643. CLASS_PRIVATE void
  1644. CWorkObject::EndExecuteWorkObject()
  1645. /*++
  1646. Abstract:
  1647. End a job, this does not terminate job currently in
  1648. processing, it remove the job from work manager's in-processing
  1649. list
  1650. Parameter:
  1651. None.
  1652. Return:
  1653. None.
  1654. --*/
  1655. {
  1656. TLSASSERT(IsValid() == TRUE);
  1657. m_pWkMgr->EndProcessingScheduledJob(this);
  1658. }