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.

1218 lines
29 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1997.
  5. //
  6. // File: thdpool.c
  7. //
  8. // Contents: Home of the SPM thread pool
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 6-08-93 RichardW Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <lsapch.hxx>
  18. #define POOL_SEM_LIMIT 0x7FFFFFFF
  19. #define MAX_POOL_THREADS_HARD 256
  20. #define MAX_SUBQUEUE_THREADS (4 * MAX_POOL_THREADS_HARD)
  21. LSAP_TASK_QUEUE GlobalQueue;
  22. //
  23. // Local Prototypes:
  24. //
  25. typedef enum _LSAP_TASK_STATUS {
  26. TaskNotQueued,
  27. TaskQueued,
  28. TaskUnknown
  29. } LSAP_TASK_STATUS ;
  30. LSAP_TASK_STATUS
  31. EnqueueThreadTask(
  32. PLSAP_TASK_QUEUE pQueue,
  33. PLSAP_THREAD_TASK pTask,
  34. BOOLEAN fUrgent);
  35. #define LockQueue(q) EnterCriticalSection(&((q)->Lock))
  36. #define UnlockQueue(q) LeaveCriticalSection(&((q)->Lock))
  37. //+---------------------------------------------------------------------------
  38. //
  39. // Function: InitializeTaskQueue
  40. //
  41. // Synopsis: Initialize a Queue Structure
  42. //
  43. // Arguments: [pQueue] --
  44. // [Type] --
  45. //
  46. // History: 11-10-95 RichardW Created
  47. //
  48. // Notes:
  49. //
  50. //----------------------------------------------------------------------------
  51. BOOL
  52. InitializeTaskQueue(
  53. PLSAP_TASK_QUEUE pQueue,
  54. LSAP_TASK_QUEUE_TYPE Type
  55. )
  56. {
  57. OBJECT_HANDLE_FLAG_INFORMATION FlagInfo ;
  58. RtlZeroMemory( pQueue, sizeof(LSAP_TASK_QUEUE) );
  59. InitializeListHead(
  60. &pQueue->pTasks
  61. );
  62. pQueue->Type = Type;
  63. pQueue->hSemaphore = CreateSemaphore(NULL, 0, POOL_SEM_LIMIT, NULL);
  64. if (!pQueue->hSemaphore)
  65. {
  66. return FALSE;
  67. }
  68. if ( FALSE == InitializeCriticalSectionAndSpinCount(
  69. &pQueue->Lock,
  70. LsaTuningParameters.CritSecSpinCount
  71. ))
  72. {
  73. NtClose( pQueue->hSemaphore );
  74. pQueue->hSemaphore = NULL ;
  75. return FALSE;
  76. }
  77. FlagInfo.Inherit = FALSE ;
  78. FlagInfo.ProtectFromClose = TRUE ;
  79. NtSetInformationObject(
  80. pQueue->hSemaphore,
  81. ObjectHandleFlagInformation,
  82. &FlagInfo,
  83. sizeof( FlagInfo ) );
  84. pQueue->StartSync = CreateEvent( NULL, TRUE, FALSE, NULL );
  85. if ( pQueue->StartSync == NULL )
  86. {
  87. DebugLog(( DEB_ERROR, "Could not create start sync event\n" ));
  88. NtClose( pQueue->hSemaphore );
  89. pQueue->hSemaphore = NULL;
  90. DeleteCriticalSection( &pQueue->Lock );
  91. return FALSE ;
  92. }
  93. return( TRUE );
  94. }
  95. //+---------------------------------------------------------------------------
  96. //
  97. // Function: InitializeThreadPool
  98. //
  99. // Synopsis: Initializes necessary data for the thread pool
  100. //
  101. // Arguments: (none)
  102. //
  103. // History: 7-13-93 RichardW Created
  104. //
  105. // Notes:
  106. //
  107. //----------------------------------------------------------------------------
  108. BOOL
  109. InitializeThreadPool(void)
  110. {
  111. if (!InitializeTaskQueue(&GlobalQueue, QueueShared))
  112. {
  113. return( FALSE );
  114. }
  115. return(TRUE);
  116. }
  117. //+---------------------------------------------------------------------------
  118. //
  119. // Function: QueueAssociateThread
  120. //
  121. // Synopsis: Associates the thread with the queue
  122. //
  123. // Arguments: [pQueue] --
  124. //
  125. // History: 11-09-95 RichardW Created
  126. //
  127. // Notes:
  128. //
  129. //----------------------------------------------------------------------------
  130. VOID
  131. QueueAssociateThread(
  132. PLSAP_TASK_QUEUE pQueue)
  133. {
  134. PSession pSession;
  135. LockQueue( pQueue );
  136. pQueue->TotalThreads++ ;
  137. //
  138. // Update the statistics:
  139. //
  140. if ( pQueue->MaxThreads < pQueue->TotalThreads )
  141. {
  142. pQueue->MaxThreads = pQueue->TotalThreads ;
  143. }
  144. UnlockQueue( pQueue );
  145. }
  146. //+---------------------------------------------------------------------------
  147. //
  148. // Function: QueueDisassociateThread
  149. //
  150. // Synopsis: Disconnects a thread and a queue
  151. //
  152. // Arguments: [pQueue] --
  153. // [pLastThread] -- OPTIONAL flag indicating last thread of queue
  154. //
  155. // History: 11-09-95 RichardW Created
  156. //
  157. // Notes:
  158. //
  159. //----------------------------------------------------------------------------
  160. BOOL
  161. QueueDisassociateThread(
  162. PLSAP_TASK_QUEUE pQueue,
  163. BOOLEAN * pLastThread)
  164. {
  165. PSession pSession;
  166. LockQueue( pQueue );
  167. DsysAssert(pQueue->TotalThreads > 0);
  168. if ( pQueue->TotalThreads == 1 )
  169. {
  170. if ( pLastThread )
  171. {
  172. *pLastThread = TRUE ;
  173. //
  174. // If the queue is being run down, set the
  175. // event since we are the last thread
  176. //
  177. if ( pQueue->Type == QueueZombie )
  178. {
  179. SetEvent( pQueue->StartSync );
  180. }
  181. }
  182. if ( pQueue->Tasks )
  183. {
  184. //
  185. // Make sure that we never have more tasks queued
  186. // to a zombie
  187. //
  188. DsysAssert( pQueue->Type != QueueZombie );
  189. UnlockQueue( pQueue );
  190. return FALSE ;
  191. }
  192. }
  193. pQueue->TotalThreads--;
  194. UnlockQueue( pQueue );
  195. return TRUE ;
  196. }
  197. //+---------------------------------------------------------------------------
  198. //
  199. // Function: DequeueAnyTask
  200. //
  201. // Synopsis: Returns a task from this queue or any shared, if available
  202. //
  203. // Arguments: [pQueue] --
  204. //
  205. // Requires: pQueue must be locked!
  206. //
  207. // History: 11-09-95 RichardW Created
  208. //
  209. // Notes:
  210. //
  211. //----------------------------------------------------------------------------
  212. PLSAP_THREAD_TASK
  213. DequeueAnyTask(
  214. PLSAP_TASK_QUEUE pQueue)
  215. {
  216. PLSAP_THREAD_TASK pTask;
  217. PLSAP_TASK_QUEUE pShared;
  218. if ( !IsListEmpty(&pQueue->pTasks) )
  219. {
  220. pTask = (PLSAP_THREAD_TASK) RemoveHeadList(&pQueue->pTasks);
  221. pQueue->Tasks --;
  222. pQueue->TaskCounter++;
  223. //
  224. // Reset the pointers. This is required by the recovery logic
  225. // in the Enqueue function below.
  226. //
  227. pTask->Next.Flink = NULL ;
  228. pTask->Next.Blink = NULL ;
  229. return( pTask );
  230. }
  231. //
  232. // No pending on primary queue. Check secondaries:
  233. //
  234. if (pQueue->Type == QueueShared)
  235. {
  236. pShared = pQueue->pShared;
  237. while ( pShared )
  238. {
  239. PLSAP_TASK_QUEUE pPrev;
  240. DWORD WaitStatus;
  241. //
  242. // We need to wait now to change the semaphore count
  243. //
  244. WaitStatus = WaitForSingleObject(pShared->hSemaphore, 0);
  245. LockQueue( pShared );
  246. if ((WaitStatus == WAIT_OBJECT_0) && !IsListEmpty(&pShared->pTasks) )
  247. {
  248. pTask = (PLSAP_THREAD_TASK) RemoveHeadList(&pShared->pTasks);
  249. pShared->Tasks--;
  250. pShared->TaskCounter++;
  251. UnlockQueue( pShared ); // Unlock shared queue
  252. return( pTask );
  253. }
  254. pPrev = pShared;
  255. pShared = pShared->pNext;
  256. UnlockQueue( pPrev );
  257. }
  258. }
  259. return( NULL );
  260. }
  261. //+---------------------------------------------------------------------------
  262. //
  263. // Function: WaitForThreadTask
  264. //
  265. // Synopsis: Function called by queue waiters
  266. //
  267. // Arguments: [pQueue] -- Queue to wait on
  268. // [TimeOut] -- timeout in seconds
  269. //
  270. // History: 11-10-95 RichardW Created
  271. //
  272. // Notes:
  273. //
  274. //----------------------------------------------------------------------------
  275. PLSAP_THREAD_TASK
  276. WaitForThreadTask(
  277. PLSAP_TASK_QUEUE pQueue,
  278. DWORD TimeOut)
  279. {
  280. PLSAP_THREAD_TASK pTask;
  281. DWORD WaitResult;
  282. LockQueue( pQueue );
  283. pTask = DequeueAnyTask( pQueue );
  284. if (pTask)
  285. {
  286. UnlockQueue( pQueue );
  287. return( pTask );
  288. }
  289. //
  290. // No pending anywhere.
  291. //
  292. if (TimeOut == 0)
  293. {
  294. UnlockQueue( pQueue );
  295. return( NULL );
  296. }
  297. //
  298. // Principal of the loop: We do this loop so long as we were awakened
  299. // by the semaphore being released. If there was no task to pick up, then
  300. // we go back and wait again. We return NULL only after a timeout, or an
  301. // error.
  302. //
  303. do
  304. {
  305. pQueue->IdleThreads++;
  306. UnlockQueue( pQueue );
  307. WaitResult = WaitForSingleObject( pQueue->hSemaphore, TimeOut );
  308. LockQueue( pQueue );
  309. //
  310. // In between the wait returning and the lock succeeding, another
  311. // thread might have queued up a request.
  312. DsysAssert(pQueue->IdleThreads > 0);
  313. pQueue->IdleThreads--;
  314. //
  315. // In between the wait returning and the lock succeeding, another
  316. // thread might have queued up a request, so don't blindly
  317. // bail out. Check the pending count, and skip over this
  318. // exit path if something is there
  319. //
  320. if ( pQueue->Tasks == 0 )
  321. {
  322. if (WaitResult != WAIT_OBJECT_0)
  323. {
  324. UnlockQueue( pQueue );
  325. if ( WaitResult == WAIT_FAILED )
  326. {
  327. DebugLog((DEB_ERROR, "Error on waiting for semaphore, %d\n", GetLastError()));
  328. }
  329. return( NULL );
  330. }
  331. }
  332. //
  333. // If the queue type is reset to Zombie, then this queue is
  334. // being killed. Return NULL immediately. If we're the last
  335. // thread, set the event so the thread deleting the queue will
  336. // wake up in a timely fashion.
  337. //
  338. if ( pQueue->Type == QueueZombie )
  339. {
  340. UnlockQueue( pQueue );
  341. return NULL ;
  342. }
  343. pTask = DequeueAnyTask( pQueue );
  344. if (pTask)
  345. {
  346. UnlockQueue( pQueue );
  347. return( pTask );
  348. }
  349. //
  350. // Track number of times we woke up but didn't have anything to do
  351. //
  352. pQueue->MissedTasks ++ ;
  353. } while ( WaitResult != WAIT_TIMEOUT );
  354. UnlockQueue( pQueue );
  355. return( NULL );
  356. }
  357. //+---------------------------------------------------------------------------
  358. //
  359. // Function: SpmPoolThreadBase
  360. //
  361. // Synopsis: New Pool Thread Base
  362. //
  363. // Arguments: [pvQueue] -- OPTIONAL queue to use
  364. //
  365. // History: 11-09-95 RichardW Created
  366. //
  367. // Notes:
  368. //
  369. //----------------------------------------------------------------------------
  370. DWORD
  371. SpmPoolThreadBase(
  372. PVOID pvSession)
  373. {
  374. PLSAP_THREAD_TASK pTask;
  375. PLSAP_TASK_QUEUE pQueue;
  376. PSession pSession;
  377. BOOLEAN ShrinkWS = FALSE;
  378. DWORD dwResult;
  379. DWORD Timeout;
  380. PSession ThreadSession ;
  381. PSession OriginalSession ;
  382. OriginalSession = GetCurrentSession();
  383. if ( pvSession )
  384. {
  385. ThreadSession = (PSession) pvSession ;
  386. SpmpReferenceSession( ThreadSession );
  387. SetCurrentSession( ThreadSession );
  388. }
  389. else
  390. {
  391. ThreadSession = OriginalSession ;
  392. SpmpReferenceSession( ThreadSession );
  393. }
  394. pQueue = ThreadSession->SharedData->pQueue ;
  395. if (!pQueue)
  396. {
  397. pQueue = &GlobalQueue;
  398. }
  399. QueueAssociateThread( pQueue );
  400. //
  401. // Share pool threads have short lifespans. Dedicated single, or
  402. // single read threads have infinite life span.
  403. //
  404. if (pQueue->Type == QueueShared)
  405. {
  406. Timeout = LsaTuningParameters.ThreadLifespan * 1000;
  407. }
  408. else
  409. {
  410. //
  411. // If we are the dedicated thread for this queue, the timeout
  412. // is infinite. If we are a temporary thread, the timeout is
  413. // the subqueue
  414. //
  415. if ( ThreadSession->ThreadId != GetCurrentThreadId() )
  416. {
  417. Timeout = LsaTuningParameters.SubQueueLifespan ;
  418. }
  419. else
  420. {
  421. Timeout = INFINITE ;
  422. }
  423. }
  424. if ( pQueue->StartSync )
  425. {
  426. DebugLog(( DEB_TRACE, "ThreadPool: Signaling start event\n" ));
  427. //
  428. // If a queue was passed in, the caller of CreateXxxQueue is blocked
  429. // waiting for us to strobe the start sync event.
  430. //
  431. SetEvent( pQueue->StartSync );
  432. }
  433. while ( TRUE )
  434. {
  435. pTask = WaitForThreadTask( pQueue, Timeout );
  436. if ( pTask )
  437. {
  438. SetCurrentSession( pTask->pSession );
  439. dwResult = pTask->pFunction(pTask->pvParameter);
  440. #if DBG
  441. RtlCheckForOrphanedCriticalSections( NtCurrentThread() );
  442. #endif
  443. SetCurrentSession( ThreadSession );
  444. //
  445. // The session in this task was referenced during the AssignThread call.
  446. // This dereference cleans that up.
  447. //
  448. SpmpDereferenceSession(pTask->pSession);
  449. LsapFreePrivateHeap( pTask );
  450. }
  451. else
  452. {
  453. //
  454. // We can never leave the queue empty of threads if
  455. // there are still tasks pending. QueueDisassociateThread
  456. // will fail if there are tasks pending. In that case,
  457. // skip up to the top of the loop again.
  458. //
  459. if ( !QueueDisassociateThread( pQueue, &ShrinkWS ) )
  460. {
  461. continue;
  462. }
  463. //
  464. // Now that we are not part of that queue, reset our thread session
  465. //
  466. SpmpDereferenceSession( ThreadSession );
  467. SetCurrentSession( OriginalSession );
  468. if ( LsaTuningParameters.Options & TUNE_TRIM_WORKING_SET )
  469. {
  470. if (ShrinkWS)
  471. {
  472. SetProcessWorkingSetSize( GetCurrentProcess(),
  473. (SIZE_T)(-1),
  474. (SIZE_T)(-1) );
  475. }
  476. }
  477. DebugLog(( DEB_TRACE,
  478. "No tasks pending on queue %x, thread exiting\n",
  479. pQueue ));
  480. return( 0 );
  481. }
  482. }
  483. return( 0 );
  484. }
  485. //+---------------------------------------------------------------------------
  486. //
  487. // Function: EnqueueThreadTask
  488. //
  489. // Synopsis: Enqueue a task, update counts, etc.
  490. //
  491. // Arguments: [pTask] -- Task to add
  492. //
  493. // History: 7-13-93 RichardW Created
  494. //
  495. // Notes:
  496. //
  497. //----------------------------------------------------------------------------
  498. LSAP_TASK_STATUS
  499. EnqueueThreadTask(
  500. PLSAP_TASK_QUEUE pQueue,
  501. PLSAP_THREAD_TASK pTask,
  502. BOOLEAN fUrgent)
  503. {
  504. BOOLEAN NeedMoreThreads = FALSE;
  505. HANDLE hQueueSem ;
  506. HANDLE hParentSem = NULL ;
  507. PLSAP_TASK_QUEUE pThreadQueue = NULL;
  508. PSession pSession = NULL;
  509. LockQueue(pQueue);
  510. if ( pQueue->Type == QueueZombie )
  511. {
  512. UnlockQueue( pQueue );
  513. return TaskNotQueued ;
  514. }
  515. if (fUrgent)
  516. {
  517. InsertHeadList(
  518. &pQueue->pTasks,
  519. &pTask->Next
  520. );
  521. }
  522. else
  523. {
  524. InsertTailList(
  525. &pQueue->pTasks,
  526. &pTask->Next
  527. );
  528. }
  529. pQueue->Tasks++;
  530. pQueue->QueuedCounter++;
  531. if ( pQueue->Tasks > pQueue->TaskHighWater )
  532. {
  533. pQueue->TaskHighWater = pQueue->Tasks ;
  534. }
  535. if (pQueue->Type == QueueShared)
  536. {
  537. if ((pQueue->Tasks > pQueue->IdleThreads) &&
  538. (pQueue->TotalThreads < MAX_POOL_THREADS_HARD))
  539. {
  540. NeedMoreThreads = TRUE;
  541. pThreadQueue = pQueue;
  542. }
  543. hParentSem = NULL ;
  544. }
  545. else if (pQueue->Type == QueueShareRead )
  546. {
  547. DsysAssert( pQueue->pOriginal );
  548. //
  549. // Here's the race potential. If the queue we have has no idle thread,
  550. // then make sure there is an idle thread at the parent queue, otherwise
  551. // we can deadlock (e.g. this call is in response to the job being executed
  552. // by the dedicated thread. Of course, this can also be a problem correctly
  553. // determining the parent queue's status, since locks should always flow down,
  554. // not up. So, if the number of jobs that we have pending exceeds the number
  555. // of idle threads, *always*, regardless of the other queue's real state or
  556. // total threads, queue up another thread.
  557. //
  558. if ( pQueue->Tasks > pQueue->IdleThreads )
  559. {
  560. NeedMoreThreads = TRUE ;
  561. pSession = pTask->pSession ;
  562. if ( pQueue->TotalThreads < MAX_SUBQUEUE_THREADS )
  563. {
  564. pThreadQueue = pQueue ;
  565. }
  566. else
  567. {
  568. pThreadQueue = pQueue->pOriginal;
  569. }
  570. }
  571. //
  572. // This is a safe read. The semaphore is not subject to change after creation,
  573. // and the worst that can happen is a bad handle.
  574. //
  575. hParentSem = pQueue->pOriginal->hSemaphore ;
  576. }
  577. hQueueSem = pQueue->hSemaphore ;
  578. UnlockQueue( pQueue );
  579. //
  580. // Kick our semaphore.
  581. //
  582. ReleaseSemaphore( hQueueSem, 1, NULL );
  583. //
  584. // Kick the parent semaphore
  585. //
  586. if ( hParentSem )
  587. {
  588. ReleaseSemaphore( hParentSem, 1, NULL );
  589. }
  590. if (NeedMoreThreads)
  591. {
  592. HANDLE hThread;
  593. DWORD tid;
  594. DebugLog((DEB_TRACE_QUEUE, "Queue %x needs more threads\n", pQueue));
  595. //
  596. // Increment the number of threads now so we don't create more threads
  597. // while we wait for the first one to be created.
  598. //
  599. InterlockedIncrement( &pThreadQueue->ReqThread );
  600. //
  601. // If the queue is a dedicated queue, supply the session from the task.
  602. // if the queue is a shared (global) queue, pass in NULL:
  603. //
  604. hThread = LsapCreateThread( NULL, 0,
  605. SpmPoolThreadBase,
  606. (pThreadQueue->Type == QueueShareRead ?
  607. pThreadQueue->OwnerSession : NULL ),
  608. 0, &tid);
  609. //
  610. // Check for failure
  611. //
  612. if (hThread == NULL)
  613. {
  614. //
  615. // This is extremely painful. The thread creation attempt
  616. // failed, but because of the nature of the queue, we don't
  617. // know if it was picked up and executed, or it was dropped,
  618. // or anything about it.
  619. //
  620. return TaskUnknown ;
  621. }
  622. else
  623. {
  624. NtClose(hThread);
  625. }
  626. }
  627. return TaskQueued ;
  628. }
  629. //+---------------------------------------------------------------------------
  630. //
  631. // Function: SpmAssignThread
  632. //
  633. // Synopsis: Assigns a task to a thread pool thread.
  634. //
  635. // Arguments: [pFunction] -- Function to execute
  636. // [pvParameter] -- Parameter to function
  637. // [pSession] -- Session to execute as
  638. //
  639. // History: 11-24-93 RichardW Created
  640. //
  641. // Notes:
  642. //
  643. //----------------------------------------------------------------------------
  644. PVOID
  645. LsapAssignThread(
  646. LPTHREAD_START_ROUTINE pFunction,
  647. PVOID pvParameter,
  648. PSession pSession,
  649. BOOLEAN fUrgent)
  650. {
  651. PLSAP_THREAD_TASK pTask;
  652. PLSAP_TASK_QUEUE pQueue;
  653. LSAP_TASK_STATUS TaskStatus ;
  654. pTask = (PLSAP_THREAD_TASK) LsapAllocatePrivateHeap( sizeof( LSAP_THREAD_TASK ) );
  655. if (!pTask)
  656. {
  657. return( NULL );
  658. }
  659. pTask->pFunction = pFunction;
  660. pTask->pvParameter = pvParameter;
  661. pTask->pSession = pSession;
  662. if ( pSession->SharedData->pQueue )
  663. {
  664. LockSession(pSession);
  665. if( pSession->SharedData->pQueue )
  666. {
  667. pQueue = pSession->SharedData->pQueue;
  668. } else
  669. {
  670. pQueue = &GlobalQueue;
  671. }
  672. UnlockSession(pSession);
  673. }
  674. else
  675. {
  676. pQueue = &GlobalQueue;
  677. }
  678. //
  679. // Reference the session so that it will never go away while a thread
  680. // is working on this task. The worker function will deref the session.
  681. //
  682. SpmpReferenceSession( pSession );
  683. TaskStatus = EnqueueThreadTask( pQueue,
  684. pTask,
  685. fUrgent );
  686. if ( ( TaskStatus == TaskQueued ) ||
  687. ( TaskStatus == TaskUnknown ) )
  688. {
  689. return pTask ;
  690. }
  691. if ( TaskStatus == TaskNotQueued )
  692. {
  693. //
  694. // Failed, therefore deref this session.
  695. //
  696. SpmpDereferenceSession( pSession );
  697. LsapFreePrivateHeap( pTask );
  698. }
  699. return NULL ;
  700. }
  701. //+---------------------------------------------------------------------------
  702. //
  703. // Function: CreateSubordinateQueue
  704. //
  705. // Synopsis: Create a Queue hanging off an original queue.
  706. //
  707. // Arguments: [pQueue] --
  708. // [pOriginalQueue] --
  709. //
  710. // History: 11-17-95 RichardW Created
  711. //
  712. // Notes:
  713. //
  714. //----------------------------------------------------------------------------
  715. BOOL
  716. CreateSubordinateQueue(
  717. PSession pSession,
  718. PLSAP_TASK_QUEUE pOriginalQueue
  719. )
  720. {
  721. HANDLE hThread;
  722. DWORD tid;
  723. PLSAP_TASK_QUEUE pQueue ;
  724. pQueue = (LSAP_TASK_QUEUE *) LsapAllocatePrivateHeap( sizeof( LSAP_TASK_QUEUE ) );
  725. if ( !pQueue )
  726. {
  727. return FALSE ;
  728. }
  729. DebugLog(( DEB_TRACE_QUEUE, "Creating sub queue %x\n", pQueue ));
  730. if (InitializeTaskQueue( pQueue, QueueShareRead ))
  731. {
  732. hThread = LsapCreateThread(NULL,
  733. 0,
  734. SpmPoolThreadBase,
  735. pSession,
  736. CREATE_SUSPENDED,
  737. &pSession->ThreadId);
  738. if (hThread == NULL)
  739. {
  740. NtClose( pQueue->StartSync );
  741. NtClose( pQueue->hSemaphore );
  742. RtlDeleteCriticalSection( &pQueue->Lock );
  743. LsapFreePrivateHeap( pQueue );
  744. pQueue = NULL;
  745. return FALSE;
  746. }
  747. else
  748. {
  749. LockQueue( pQueue );
  750. LockQueue( pOriginalQueue );
  751. pQueue->pNext = pOriginalQueue->pShared;
  752. pOriginalQueue->pShared = pQueue;
  753. pQueue->pOriginal = pOriginalQueue;
  754. pQueue->OwnerSession = pSession ;
  755. UnlockQueue( pOriginalQueue );
  756. UnlockQueue( pQueue );
  757. pSession->SharedData->pQueue = pQueue ;
  758. ResumeThread( hThread );
  759. NtClose( hThread );
  760. //
  761. // Wait for the thread to signal the event, so that
  762. // we know it's ready
  763. //
  764. WaitForSingleObject( pQueue->StartSync, INFINITE );
  765. NtClose( pQueue->StartSync );
  766. pQueue->StartSync = NULL ;
  767. return TRUE;
  768. }
  769. }
  770. LsapFreePrivateHeap( pQueue );
  771. return FALSE;
  772. }
  773. //+---------------------------------------------------------------------------
  774. //
  775. // Function: DeleteSubordinateQueue
  776. //
  777. // Synopsis:
  778. //
  779. // Effects:
  780. //
  781. // Arguments: [pQueue] --
  782. //
  783. // Requires:
  784. //
  785. // Returns:
  786. //
  787. // Signals:
  788. //
  789. // Modifies:
  790. //
  791. // Algorithm:
  792. //
  793. // History: 8-05-96 RichardW Created
  794. //
  795. // Notes:
  796. //
  797. //----------------------------------------------------------------------------
  798. BOOL
  799. DeleteSubordinateQueue(
  800. PLSAP_TASK_QUEUE pQueue,
  801. ULONG Flags)
  802. {
  803. PLSAP_TASK_QUEUE pOriginal;
  804. PLSAP_THREAD_TASK pTask ;
  805. DWORD dwResult ;
  806. PLIST_ENTRY List ;
  807. PSession ThreadSession = GetCurrentSession();
  808. OBJECT_HANDLE_FLAG_INFORMATION FlagInfo ;
  809. //
  810. // Lock it
  811. //
  812. DebugLog(( DEB_TRACE, "Deleting queue %x\n", pQueue ));
  813. LockQueue( pQueue );
  814. if ( pQueue->pShared )
  815. {
  816. pOriginal = pQueue->pOriginal ;
  817. LockQueue( pOriginal );
  818. //
  819. // Unlink Queue from parent:
  820. //
  821. if ( pOriginal->pShared != pQueue )
  822. {
  823. PLSAP_TASK_QUEUE pScan = pOriginal->pShared;
  824. LockQueue( pScan );
  825. while ( pScan->pNext && (pScan->pNext != pQueue) )
  826. {
  827. pScan = pScan->pNext;
  828. }
  829. if ( pScan->pNext )
  830. {
  831. pScan->pNext = pQueue->pNext ;
  832. }
  833. UnlockQueue( pScan );
  834. }
  835. else
  836. {
  837. pOriginal->pShared = pQueue->pNext;
  838. }
  839. pQueue->pNext = NULL ;
  840. //
  841. // Done with parent
  842. //
  843. UnlockQueue( pOriginal );
  844. }
  845. //
  846. // Drain queue by removing all the tasks.
  847. //
  848. while ( !IsListEmpty( &pQueue->pTasks ) )
  849. {
  850. List = RemoveHeadList( &pQueue->pTasks );
  851. pQueue->Tasks-- ;
  852. pTask = CONTAINING_RECORD( List, LSAP_THREAD_TASK, Next );
  853. //
  854. // A synchronous drain will have this thread execute
  855. // all remaining tasks.
  856. //
  857. if ( Flags & DELETEQ_SYNC_DRAIN )
  858. {
  859. SpmpReferenceSession(pTask->pSession);
  860. SetCurrentSession( pTask->pSession );
  861. dwResult = pTask->pFunction(pTask->pvParameter);
  862. SetCurrentSession( ThreadSession );
  863. SpmpDereferenceSession(pTask->pSession);
  864. LsapFreePrivateHeap( pTask );
  865. }
  866. else
  867. {
  868. //
  869. // Otherwise, send them to the global queue to be
  870. // executed by other threads
  871. //
  872. EnqueueThreadTask(
  873. &GlobalQueue,
  874. pTask,
  875. FALSE );
  876. }
  877. }
  878. //
  879. // Now, kill off all the threads
  880. //
  881. pQueue->Type = QueueZombie ;
  882. //
  883. // We might be executing on our own worker thread. If there are
  884. // more than one thread associated with this queue, we also
  885. // need to do the sync.
  886. //
  887. if ( ( pQueue->OwnerSession != ThreadSession ) ||
  888. ( pQueue->TotalThreads > 1 ) )
  889. {
  890. //
  891. // We are not a worker thread. Sync with the other
  892. // threads to clean up:
  893. //
  894. pQueue->StartSync = CreateEvent( NULL, FALSE, FALSE, NULL );
  895. //
  896. // Kick the semaphore for all the threads that need it
  897. // (all of them if we aren't a worker thread, or n-1 if
  898. // we are:
  899. //
  900. ReleaseSemaphore(
  901. pQueue->hSemaphore,
  902. (pQueue->OwnerSession == ThreadSession ?
  903. pQueue->TotalThreads - 1 :
  904. pQueue->TotalThreads),
  905. NULL );
  906. UnlockQueue( pQueue );
  907. //
  908. // if we failed to create an event, then we may cause an invalid handle
  909. // problem in the client threads. Sleep a little to let the other threads
  910. // go (hopefully), then close the semaphore and let the error handling
  911. // in the threads deal with it.
  912. //
  913. if ( pQueue->StartSync )
  914. {
  915. WaitForSingleObjectEx( pQueue->StartSync, INFINITE, FALSE );
  916. //
  917. // Synchronize with the last thread to own the queue:
  918. //
  919. LockQueue( pQueue );
  920. NtClose( pQueue->StartSync );
  921. pQueue->StartSync = NULL ;
  922. }
  923. else
  924. {
  925. //
  926. // kludge up a retry loop:
  927. //
  928. int i = 50 ;
  929. while ( i && pQueue->TotalThreads )
  930. {
  931. Sleep( 100 );
  932. i-- ;
  933. }
  934. //
  935. // If they're still there, forget it. Return FALSE. Leak.
  936. //
  937. if ( pQueue->TotalThreads )
  938. {
  939. return FALSE ;
  940. }
  941. }
  942. }
  943. //
  944. // At this point, we close the queue down:
  945. //
  946. FlagInfo.Inherit = FALSE ;
  947. FlagInfo.ProtectFromClose = FALSE ;
  948. NtSetInformationObject(
  949. pQueue->hSemaphore,
  950. ObjectHandleFlagInformation,
  951. &FlagInfo,
  952. sizeof( FlagInfo ) );
  953. NtClose( pQueue->hSemaphore );
  954. UnlockQueue( pQueue );
  955. RtlDeleteCriticalSection( &pQueue->Lock );
  956. LsapFreePrivateHeap( pQueue );
  957. return( TRUE );
  958. }