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.

2910 lines
77 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. atqmain.cxx
  5. Abstract:
  6. This module implements entry points for ATQ - Asynchronous Thread Queue.
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 8-Apr-1996
  9. Environment:
  10. User Mode -- Win32
  11. Project:
  12. Internet Services Common DLL
  13. Functions Exported:
  14. BOOL AtqInitialize();
  15. BOOL AtqTerminate();
  16. BOOL AtqGetCompletionPort();
  17. DWORD AtqSetInfo();
  18. DWORD AtqGetInfo();
  19. BOOL AtqGetStatistics();
  20. BOOL AtqClearStatistics();
  21. BOOL AtqAddAcceptExSockets();
  22. BOOL AtqAddAsyncHandle();
  23. DWORD AtqContextSetInfo();
  24. VOID AtqCloseSocket();
  25. VOID AtqFreeContext();
  26. BOOL AtqReadFile();
  27. BOOL AtqWriteFile();
  28. BOOL AtqTransmitFile();
  29. BOOL AtqPostCompletionStatus();
  30. PVOID AtqAllocateBandwidthInfo();
  31. BOOL AtqFreeBandwidthInfo();
  32. DWORD AtqBandwidthSetInfo();
  33. --*/
  34. #include "isatq.hxx"
  35. #include <iscaptrc.h>
  36. # define ATQ_REG_DEF_THREAD_TIMEOUT_PWS (30*60) // 30 minutes
  37. /************************************************************
  38. * Globals
  39. ************************************************************/
  40. //
  41. // specifies the registry location to use for getting the ATQ Configuration
  42. // (Global overrides)
  43. //
  44. CHAR g_PSZ_ATQ_CONFIG_PARAMS_REG_KEY[] =
  45. TEXT("System\\CurrentControlSet\\Services\\InetInfo\\Parameters");
  46. // ----------------------------------------
  47. // # of CPUs in machine (for thread-tuning)
  48. // ----------------------------------------
  49. DWORD g_cCPU = 0;
  50. //
  51. // concurrent # of threads to run per processor
  52. //
  53. DWORD g_cConcurrency = ATQ_REG_DEF_PER_PROCESSOR_CONCURRENCY;
  54. //
  55. // Amount of time (in ms) a worker thread will be idle before suicide
  56. //
  57. DWORD g_msThreadTimeout = ATQ_REG_DEF_THREAD_TIMEOUT * 1000;
  58. BOOL g_fUseAcceptEx = TRUE; // Use AcceptEx if available
  59. //
  60. // The absolute thread limit
  61. //
  62. LONG g_cMaxThreadLimit = ATQ_REG_DEF_POOL_THREAD_LIMIT;
  63. //
  64. // Assumed minimum file transfer rate
  65. //
  66. DWORD g_cbMinKbSec = ATQ_REG_DEF_MIN_KB_SEC;
  67. //
  68. // number of active context list
  69. //
  70. DWORD g_dwNumContextLists = ATQ_NUM_CONTEXT_LIST;
  71. /*
  72. g_pfnExitThreadCallback()
  73. This routine sets the callback routine to be called when one of the
  74. Atq threads exit so that thread state data can be cleaned up. Currently
  75. support is for a single routine. One way to support multiple routines would
  76. be for the caller to save the return value. Such an application would not
  77. be able to delete the "saved" callback routine.
  78. */
  79. ATQ_THREAD_EXIT_CALLBACK g_pfnExitThreadCallback = NULL;
  80. //
  81. // mswsock entry points
  82. //
  83. HINSTANCE g_hMSWsock = NULL;
  84. PFN_ACCEPTEX g_pfnAcceptEx = NULL;
  85. PFN_GETACCEPTEXSOCKADDRS g_pfnGetAcceptExSockaddrs = NULL;
  86. PFN_TRANSMITFILE g_pfnTransmitFile = NULL;
  87. PFN_GET_QUEUED_COMPLETION_STATUS g_pfnGetQueuedCompletionStatus = NULL;
  88. PFN_CREATE_COMPLETION_PORT g_pfnCreateCompletionPort = NULL;
  89. PFN_CLOSE_COMPLETION_PORT g_pfnCloseCompletionPort = NULL;
  90. PFN_POST_COMPLETION_STATUS g_pfnPostCompletionStatus = NULL;
  91. //
  92. // NT specific
  93. //
  94. PFN_READ_DIR_CHANGES_W g_pfnReadDirChangesW = NULL;
  95. // ------------------------------
  96. // Current State Information
  97. // ------------------------------
  98. HANDLE g_hCompPort = NULL; // Handle for completion port
  99. LONG g_cThreads = 0; // number of thread in the pool
  100. LONG g_cAvailableThreads = 0; // # of threads waiting on the port.
  101. //
  102. // Should we use the TF_USE_KERNEL_APC flag for TransmitFile
  103. //
  104. BOOL g_fUseKernelApc = ATQ_REG_DEF_USE_KERNEL_APC;
  105. //
  106. // Current thread limit
  107. //
  108. LONG g_cMaxThreads = ATQ_REG_DEF_PER_PROCESSOR_ATQ_THREADS;
  109. DWORD g_cListenBacklog = ATQ_REG_DEF_LISTEN_BACKLOG;
  110. BOOL g_fShutdown = FALSE; // if set, indicates that we are shutting down
  111. // in that case, all threads should exit.
  112. HANDLE g_hShutdownEvent = NULL; // set when all running threads shutdown
  113. BOOL g_fEnableDebugThreads = FALSE; // if TRUE, debug IO threads can be
  114. // created
  115. BOOL g_fCreateDebugThread = FALSE; // set to TRUE to create a debug thread
  116. // ------------------------------
  117. // Bandwidth Throttling Info
  118. // ------------------------------
  119. PBANDWIDTH_INFO g_pBandwidthInfo = NULL;
  120. // ------------------------------
  121. // Various State/Object Lists
  122. // ------------------------------
  123. //
  124. // Used to switch context between lists
  125. //
  126. DWORD AtqGlobalContextCount = 0;
  127. //
  128. // List of active context
  129. //
  130. ATQ_CONTEXT_LISTHEAD AtqActiveContextList[ATQ_NUM_CONTEXT_LIST];
  131. //
  132. // List of Endpoints in ATQ - one per listen socket
  133. //
  134. LIST_ENTRY AtqEndpointList;
  135. CRITICAL_SECTION AtqEndpointLock;
  136. PALLOC_CACHE_HANDLER g_pachAtqContexts;
  137. #ifdef IIS_AUX_COUNTERS
  138. LONG g_AuxCounters[NUM_AUX_COUNTERS];
  139. #endif // IIS_AUX_COUNTERS
  140. //
  141. // Timeout before closing pending listens in case backlog is full
  142. //
  143. DWORD g_cForceTimeout;
  144. //
  145. // Flag enabling/disabling the backlog monitor
  146. //
  147. BOOL g_fDisableBacklogMonitor = FALSE;
  148. // ------------------------------
  149. // local to this module
  150. // ------------------------------
  151. LONG sg_AtqInitializeCount = -1;
  152. HANDLE g_hCapThread = NULL;
  153. DWORD
  154. I_AtqGetGlobalConfiguration(VOID);
  155. DWORD
  156. I_NumAtqEndpointsOpen(VOID);
  157. DWORD
  158. AtqDebugCreatorThread(
  159. LPDWORD param
  160. );
  161. //
  162. // Capacity Planning variables
  163. //
  164. extern TRACEHANDLE IISCapTraceRegistrationHandle;
  165. //
  166. // Ensure that initialization/termination don't happen at the same time
  167. //
  168. CRITICAL_SECTION g_csInitTermLock;
  169. /************************************************************
  170. * Functions
  171. ************************************************************/
  172. BOOL
  173. AtqInitialize(
  174. IN DWORD dwFlags
  175. )
  176. /*++
  177. Routine Description:
  178. Initializes the ATQ package
  179. Arguments:
  180. dwFlags - DWORD containing the flags for use to initialize ATQ library.
  181. This dword helps to shut off the unwanted flags.
  182. Return Value:
  183. TRUE if successful, FALSE on error (call GetLastError)
  184. Note:
  185. As of 4/16/97 the pszRegKey that is sent is no more utilized.
  186. We always load the internal configuration parameters from
  187. one single registry entry specified by PSZ_ATQ_CONFIG_PARAMS_REG_KEY
  188. The parameter is left in the command line for compatibility
  189. with old callers :( - NYI: Need to change this.
  190. --*/
  191. {
  192. DWORD i;
  193. DWORD dwThreadID;
  194. DBGPRINTF(( DBG_CONTEXT, "AtqInitialize, %d, %x\n",
  195. sg_AtqInitializeCount, dwFlags));
  196. if ( InterlockedIncrement( &sg_AtqInitializeCount) != 0) {
  197. IF_DEBUG( API_ENTRY) {
  198. ATQ_PRINTF(( DBG_CONTEXT,
  199. "AtqInitialize( %08x). ATQ is already initialized.\n",
  200. dwFlags));
  201. }
  202. //
  203. // we are already initialized. Ignore the new registry settings
  204. //
  205. return ( TRUE);
  206. }
  207. EnterCriticalSection( &g_csInitTermLock );
  208. IF_DEBUG( API_ENTRY) {
  209. ATQ_PRINTF(( DBG_CONTEXT,
  210. "AtqInitialize[%08x]. Initializing....\n",
  211. dwFlags));
  212. }
  213. // get the number of processors for this machine
  214. // do it only for NT Server only (don't scale workstation)
  215. if ( TsIsNtServer() ) {
  216. SYSTEM_INFO si;
  217. GetSystemInfo( &si );
  218. g_cCPU = si.dwNumberOfProcessors;
  219. } else {
  220. g_cCPU = 1;
  221. }
  222. //
  223. // Initialize context lists and crit sects
  224. //
  225. ATQ_CONTEXT_LISTHEAD * pacl;
  226. for ( pacl = AtqActiveContextList;
  227. pacl < (AtqActiveContextList + g_dwNumContextLists);
  228. pacl++) {
  229. pacl->Initialize();
  230. }
  231. InitializeListHead( &AtqEndpointList );
  232. //
  233. // init bandwidth throttling
  234. //
  235. ATQ_REQUIRE( BANDWIDTH_INFO::AbwInitialize() );
  236. //
  237. // Read registry configurable Atq options. We have to read these now
  238. // because concurrency is set for the completion port at creation time.
  239. //
  240. DWORD dwError = I_AtqGetGlobalConfiguration();
  241. if ( NO_ERROR != dwError) {
  242. SetLastError( dwError );
  243. goto cleanup;
  244. }
  245. //
  246. // Setup an allocation cache for the ATQ Contexts
  247. // NYI: Auto-tune the threshold limit
  248. //
  249. {
  250. ALLOC_CACHE_CONFIGURATION acConfig;
  251. DWORD nCachedAtq = ATQ_CACHE_LIMIT_NTS;
  252. acConfig.nConcurrency = 1;
  253. acConfig.nThreshold = nCachedAtq;
  254. acConfig.cbSize = sizeof(ATQ_CONTEXT);
  255. g_pachAtqContexts = new ALLOC_CACHE_HANDLER( "ATQ", &acConfig);
  256. if ( NULL == g_pachAtqContexts) {
  257. goto cleanup;
  258. }
  259. }
  260. //
  261. // Create the shutdown event
  262. //
  263. g_hShutdownEvent = IIS_CREATE_EVENT(
  264. "g_hShutdownEvent",
  265. &g_hShutdownEvent,
  266. TRUE, // Manual reset
  267. FALSE // Not signalled
  268. );
  269. if ( !g_hShutdownEvent ) {
  270. DBGERROR(( DBG_CONTEXT, "Create Shutdown event failed. Last Error = 0x%x\n",
  271. GetLastError()
  272. ));
  273. goto cleanup;
  274. }
  275. //
  276. // Create the completion port
  277. //
  278. g_hCompPort = g_pfnCreateCompletionPort(INVALID_HANDLE_VALUE,
  279. NULL,
  280. 0,
  281. g_cConcurrency
  282. );
  283. if ( !g_hCompPort ) {
  284. DBGERROR(( DBG_CONTEXT, "Create IoComp port failed. Last Error = 0x%x\n",
  285. GetLastError()
  286. ));
  287. goto cleanup;
  288. }
  289. //
  290. // Initialize Backlog Monitor
  291. //
  292. if ( !g_fDisableBacklogMonitor )
  293. {
  294. DBG_ASSERT( g_pAtqBacklogMonitor == NULL );
  295. g_pAtqBacklogMonitor = new ATQ_BACKLOG_MONITOR;
  296. if (!g_pAtqBacklogMonitor) {
  297. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  298. goto cleanup;
  299. }
  300. }
  301. //
  302. // Ensure all other initializations also are done
  303. //
  304. g_cThreads = 0;
  305. g_fShutdown = FALSE;
  306. g_cAvailableThreads = 0;
  307. if ( !I_AtqStartTimeoutProcessing( NULL ) ) {
  308. goto cleanup;
  309. }
  310. IF_DEBUG(INIT_CLEAN) {
  311. DBGPRINTF(( DBG_CONTEXT,
  312. "fUseAcceptEx[%d] NT CompPort[1] Platform[%d]\n",
  313. g_fUseAcceptEx,
  314. IISPlatformType()
  315. ));
  316. }
  317. //
  318. // Create the initial ATQ thread.
  319. //
  320. (VOID)I_AtqCheckThreadStatus( (PVOID)ATQ_INITIAL_THREAD );
  321. //
  322. // Create a second thread if we are NTS
  323. //
  324. if ( TsIsNtServer() ) {
  325. (VOID)I_AtqCheckThreadStatus( (PVOID)ATQ_INITIAL_THREAD );
  326. }
  327. //
  328. // Initialize Capacity Planning Trace
  329. //
  330. // Spawn another thread to do this since IISInitializeCapTrace() can
  331. // take a while and we are not in a state where SCM is getting
  332. // SERVICE_STARTING messages
  333. //
  334. g_hCapThread = CreateThread( NULL,
  335. 0,
  336. IISInitializeCapTrace,
  337. NULL,
  338. 0,
  339. &dwThreadID
  340. );
  341. IF_DEBUG( API_EXIT) {
  342. ATQ_PRINTF(( DBG_CONTEXT,
  343. "AtqInitialize( %08x) returns %d.\n",
  344. dwFlags, TRUE));
  345. }
  346. //
  347. // Create the debug thread starter if necessary
  348. //
  349. if ( g_fEnableDebugThreads )
  350. {
  351. DWORD dwError;
  352. DWORD dwThreadID;
  353. HANDLE hThread;
  354. hThread = CreateThread( NULL,
  355. 0,
  356. (LPTHREAD_START_ROUTINE)AtqDebugCreatorThread,
  357. NULL,
  358. 0,
  359. &dwThreadID );
  360. if ( !hThread )
  361. {
  362. goto cleanup;
  363. }
  364. CloseHandle( hThread );
  365. }
  366. LeaveCriticalSection( &g_csInitTermLock );
  367. return TRUE;
  368. cleanup:
  369. DWORD dwSaveError = GetLastError();
  370. for (i=0; i<g_dwNumContextLists; i++) {
  371. AtqActiveContextList[i].Cleanup();
  372. }
  373. if ( g_hShutdownEvent != NULL ) {
  374. CloseHandle( g_hShutdownEvent );
  375. g_hShutdownEvent = NULL;
  376. }
  377. if ( g_hCompPort != NULL ) {
  378. g_pfnCloseCompletionPort( g_hCompPort );
  379. g_hCompPort = NULL;
  380. }
  381. if ( NULL != g_pachAtqContexts) {
  382. delete g_pachAtqContexts;
  383. g_pachAtqContexts = NULL;
  384. }
  385. if ( NULL != g_pAtqBacklogMonitor ) {
  386. delete g_pAtqBacklogMonitor;
  387. g_pAtqBacklogMonitor = NULL;
  388. }
  389. ATQ_REQUIRE( BANDWIDTH_INFO::AbwTerminate());
  390. IF_DEBUG( API_EXIT) {
  391. ATQ_PRINTF(( DBG_CONTEXT,
  392. "AtqInitialize( %08x) returns %d.\n",
  393. dwFlags, FALSE));
  394. }
  395. sg_AtqInitializeCount = -1;
  396. SetLastError(dwSaveError);
  397. LeaveCriticalSection( &g_csInitTermLock );
  398. return(FALSE);
  399. } // AtqInitialize()
  400. BOOL
  401. AtqTerminate(
  402. VOID
  403. )
  404. /*++
  405. Routine Description:
  406. Cleans up the ATQ package. Should only be called after all of the
  407. clients of ATQ have been shutdown.
  408. Arguments:
  409. None.
  410. Return Value:
  411. TRUE, if ATQ was shutdown properly
  412. FALSE, otherwise
  413. --*/
  414. {
  415. DBGPRINTF(( DBG_CONTEXT, "AtqTerminate, %d\n", sg_AtqInitializeCount));
  416. DWORD currentThreadCount;
  417. ATQ_CONTEXT_LISTHEAD * pacl;
  418. BOOL fRet = TRUE;
  419. DWORD dwErr;
  420. // there are outstanding users, don't fully terminate
  421. if ( InterlockedDecrement( &sg_AtqInitializeCount) >= 0) {
  422. /*IF_DEBUG( API_ENTRY)*/ {
  423. ATQ_PRINTF(( DBG_CONTEXT,
  424. "AtqTerminate() - there are other users."
  425. " Not terminating now\n"
  426. ));
  427. }
  428. return (TRUE);
  429. }
  430. EnterCriticalSection( &g_csInitTermLock );
  431. /*IF_DEBUG( API_ENTRY)*/ {
  432. ATQ_PRINTF(( DBG_CONTEXT,
  433. "AtqTerminate() - Terminating ATQ ...\n"
  434. ));
  435. }
  436. //
  437. // All the ATQ endpoints should have been terminated before calling
  438. // this ATQTerminate() function. If not, sorry return failure.
  439. //
  440. DWORD nEndpointsToBeClosed = I_NumAtqEndpointsOpen();
  441. if ( nEndpointsToBeClosed > 0) {
  442. DBGPRINTF(( DBG_CONTEXT,
  443. " There are %d endpoints remaining to be closed."
  444. " Somebody above stream did not close endpoints."
  445. " BUG IN CODE ABOVE ATQ\n"
  446. ,
  447. nEndpointsToBeClosed
  448. ));
  449. SetLastError( ERROR_NETWORK_BUSY);
  450. fRet = FALSE;
  451. goto Finished;
  452. }
  453. if ( (g_hShutdownEvent == NULL) || g_fShutdown ) {
  454. //
  455. // We have not been intialized or have already terminated.
  456. //
  457. SetLastError( ERROR_NOT_READY );
  458. fRet = FALSE;
  459. goto Finished;
  460. }
  461. //
  462. // All clients should have cleaned themselves up before calling us.
  463. //
  464. for ( pacl = AtqActiveContextList;
  465. pacl < (AtqActiveContextList + g_dwNumContextLists);
  466. pacl++) {
  467. pacl->Lock();
  468. if ( !IsListEmpty(&pacl->ActiveListHead)) {
  469. ATQ_ASSERT( IsListEmpty( &pacl->ActiveListHead));
  470. pacl->Unlock();
  471. IF_DEBUG( API_EXIT) {
  472. ATQ_PRINTF(( DBG_CONTEXT,
  473. "AtqTerminate() - ContextList(%08x) has "
  474. "Active Contexts. Failed Termination.\n",
  475. pacl
  476. ));
  477. }
  478. fRet = FALSE;
  479. goto Finished;
  480. }
  481. pacl->Unlock();
  482. } // for
  483. //
  484. // Note that we are shutting down and prevent any more handles from
  485. // being added to the completion port.
  486. //
  487. g_fShutdown = TRUE;
  488. //
  489. // Attempt and remove the TimeOut Context from scheduler queue
  490. //
  491. DBG_REQUIRE( I_AtqStopTimeoutProcessing());
  492. currentThreadCount = g_cThreads;
  493. if (currentThreadCount > 0) {
  494. DWORD i;
  495. BOOL fRes;
  496. OVERLAPPED overlapped;
  497. //
  498. // Post a message to the completion port for each worker thread
  499. // telling it to exit. The indicator is a NULL context in the
  500. // completion.
  501. //
  502. ZeroMemory( &overlapped, sizeof(OVERLAPPED) );
  503. for (i=0; i<currentThreadCount; i++) {
  504. fRes = g_pfnPostCompletionStatus( g_hCompPort,
  505. 0,
  506. 0,
  507. &overlapped );
  508. ATQ_ASSERT( (fRes == TRUE) ||
  509. ( (fRes == FALSE) &&
  510. (GetLastError() == ERROR_IO_PENDING) )
  511. );
  512. }
  513. }
  514. //
  515. // Now wait for the pool threads to shutdown.
  516. //
  517. dwErr = WaitForSingleObject( g_hShutdownEvent, ATQ_WAIT_FOR_THREAD_DEATH);
  518. #if 0
  519. DWORD dwWaitCount = 0;
  520. while ( dwErr == WAIT_TIMEOUT) {
  521. dwWaitCount++;
  522. DebugBreak();
  523. Sleep( 10*1000); // sleep for some time
  524. dwErr =
  525. WaitForSingleObject( g_hShutdownEvent, ATQ_WAIT_FOR_THREAD_DEATH);
  526. } // while
  527. # endif // 0
  528. //
  529. // At this point, no other threads should be left running.
  530. //
  531. //
  532. // g_cThreads counter is decremented by AtqPoolThread().
  533. // AtqTerminate() is called during the DLL termination
  534. // But at DLL termination, all ATQ pool threads are killed =>
  535. // no one is decrementing the count. Hence this assert will always fail.
  536. //
  537. // ATQ_ASSERT( !g_cThreads );
  538. ATQ_REQUIRE( CloseHandle( g_hShutdownEvent ) );
  539. g_pfnCloseCompletionPort( g_hCompPort );
  540. g_hShutdownEvent = NULL;
  541. g_hCompPort = NULL;
  542. //
  543. // Cleanup our synchronization resources
  544. //
  545. for ( pacl = AtqActiveContextList;
  546. pacl < (AtqActiveContextList + g_dwNumContextLists);
  547. pacl++) {
  548. PLIST_ENTRY pEntry;
  549. pacl->Lock();
  550. if ( !IsListEmpty( &pacl->PendingAcceptExListHead)) {
  551. for ( pEntry = pacl->PendingAcceptExListHead.Flink;
  552. pEntry != &pacl->PendingAcceptExListHead;
  553. pEntry = pEntry->Flink ) {
  554. PATQ_CONT pContext =
  555. CONTAINING_RECORD( pEntry, ATQ_CONTEXT, m_leTimeout );
  556. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  557. pContext->Print();
  558. } // for
  559. }
  560. pacl->Unlock();
  561. pacl->Cleanup();
  562. }
  563. //
  564. // Free all the elements in the Allocation caching list
  565. //
  566. if ( NULL != g_pachAtqContexts) {
  567. delete g_pachAtqContexts;
  568. g_pachAtqContexts = NULL;
  569. }
  570. if ( g_hCapThread )
  571. {
  572. WaitForSingleObject( g_hCapThread, INFINITE );
  573. CloseHandle( g_hCapThread );
  574. g_hCapThread = NULL;
  575. if (IISCapTraceRegistrationHandle != (TRACEHANDLE)0)
  576. {
  577. UnregisterTraceGuids( IISCapTraceRegistrationHandle );
  578. }
  579. }
  580. //
  581. // cleanup backlog monitor
  582. //
  583. delete g_pAtqBacklogMonitor;
  584. g_pAtqBacklogMonitor = NULL;
  585. // Cleanup variables in ATQ Bandwidth throttle module
  586. if ( !BANDWIDTH_INFO::AbwTerminate()) {
  587. // there may be a few blocked IO. We should avoid them all.
  588. // All clients should have cleaned themselves up before coming here.
  589. fRet = FALSE;
  590. goto Finished;
  591. }
  592. if ( g_hMSWsock != NULL ) {
  593. FreeLibrary(g_hMSWsock);
  594. g_hMSWsock = NULL;
  595. }
  596. IF_DEBUG( API_EXIT) {
  597. ATQ_PRINTF(( DBG_CONTEXT,
  598. "AtqTerminate() - Successfully cleaned up.\n"
  599. ));
  600. }
  601. Finished:
  602. LeaveCriticalSection( &g_csInitTermLock );
  603. return fRet;
  604. } // AtqTerminate()
  605. HANDLE
  606. AtqGetCompletionPort()
  607. /*++
  608. Routine Description:
  609. Return the completion port created by ATQ
  610. Arguments:
  611. Return Value:
  612. Handle to ATQ completion port
  613. --*/
  614. {
  615. return g_hCompPort;
  616. } // AtqGetCompletionPort()
  617. ULONG_PTR
  618. AtqSetInfo(
  619. IN ATQ_INFO atqInfo,
  620. IN ULONG_PTR Data
  621. )
  622. /*++
  623. Routine Description:
  624. Sets various bits of information for the ATQ module
  625. Arguments:
  626. atqInfo - Data item to set
  627. data - New value for item
  628. Return Value:
  629. The old value of the parameter
  630. --*/
  631. {
  632. ULONG_PTR oldVal = 0;
  633. switch ( atqInfo ) {
  634. case AtqBandwidthThrottle:
  635. ATQ_ASSERT( g_pBandwidthInfo != NULL );
  636. oldVal = (ULONG_PTR)g_pBandwidthInfo->SetBandwidthLevel( (DWORD)Data );
  637. break;
  638. case AtqBandwidthThrottleMaxBlocked:
  639. ATQ_ASSERT( g_pBandwidthInfo != NULL );
  640. oldVal = (ULONG_PTR)g_pBandwidthInfo->SetMaxBlockedListSize( (DWORD)Data );
  641. break;
  642. case AtqExitThreadCallback:
  643. oldVal = (ULONG_PTR)g_pfnExitThreadCallback;
  644. g_pfnExitThreadCallback = (ATQ_THREAD_EXIT_CALLBACK ) Data;
  645. break;
  646. case AtqMaxPoolThreads:
  647. // the value is per processor values
  648. // internally we maintain value for all processors
  649. oldVal = (ULONG_PTR)( g_cMaxThreads/g_cCPU );
  650. g_cMaxThreads = (DWORD)Data * g_cCPU;
  651. break;
  652. //
  653. // Increment or decrement the max thread count. In this instance, we
  654. // do not scale by the number of CPUs
  655. //
  656. case AtqIncMaxPoolThreads:
  657. InterlockedIncrement( (LONG *) &g_cMaxThreads );
  658. oldVal = TRUE;
  659. break;
  660. case AtqDecMaxPoolThreads:
  661. InterlockedDecrement( (LONG *) &g_cMaxThreads );
  662. oldVal = TRUE;
  663. break;
  664. case AtqMaxConcurrency:
  665. oldVal = (ULONG_PTR)g_cConcurrency;
  666. g_cConcurrency = (DWORD)Data;
  667. break;
  668. case AtqThreadTimeout:
  669. oldVal = (ULONG_PTR)(g_msThreadTimeout/1000); // convert back to seconds
  670. g_msThreadTimeout = (DWORD)Data * 1000; // convert value to millisecs
  671. break;
  672. case AtqUseAcceptEx:
  673. oldVal = (ULONG_PTR)g_fUseAcceptEx;
  674. g_fUseAcceptEx = (DWORD)Data;
  675. break;
  676. case AtqMinKbSec:
  677. //
  678. // Ignore it if the value is zero
  679. //
  680. if ( Data ) {
  681. oldVal = (ULONG_PTR)g_cbMinKbSec;
  682. g_cbMinKbSec = (DWORD)Data;
  683. }
  684. break;
  685. default:
  686. ATQ_ASSERT( FALSE );
  687. break;
  688. }
  689. return oldVal;
  690. } // AtqSetInfo()
  691. ULONG_PTR
  692. AtqGetInfo(
  693. IN ATQ_INFO atqInfo
  694. )
  695. /*++
  696. Routine Description:
  697. Gets various bits of information for the ATQ module
  698. Arguments:
  699. atqInfo - Data item to set
  700. Return Value:
  701. The old value of the parameter
  702. --*/
  703. {
  704. ULONG_PTR dwVal = 0;
  705. switch ( atqInfo ) {
  706. case AtqBandwidthThrottle:
  707. ATQ_ASSERT( g_pBandwidthInfo != NULL );
  708. dwVal = (ULONG_PTR ) g_pBandwidthInfo->QueryBandwidthLevel();
  709. break;
  710. case AtqExitThreadCallback:
  711. dwVal = (ULONG_PTR ) g_pfnExitThreadCallback;
  712. break;
  713. case AtqMaxPoolThreads:
  714. dwVal = (ULONG_PTR ) (g_cMaxThreads/g_cCPU);
  715. break;
  716. case AtqMaxConcurrency:
  717. dwVal = (ULONG_PTR ) g_cConcurrency;
  718. break;
  719. case AtqThreadTimeout:
  720. dwVal = (ULONG_PTR ) (g_msThreadTimeout/1000); // convert back to seconds
  721. break;
  722. case AtqUseAcceptEx:
  723. dwVal = (ULONG_PTR ) g_fUseAcceptEx;
  724. break;
  725. case AtqMinKbSec:
  726. dwVal = (ULONG_PTR ) g_cbMinKbSec;
  727. break;
  728. case AtqMaxThreadLimit:
  729. dwVal = (ULONG_PTR ) g_cMaxThreadLimit;
  730. break;
  731. case AtqAvailableThreads:
  732. dwVal = (ULONG_PTR) g_cAvailableThreads;
  733. break;
  734. default:
  735. ATQ_ASSERT( FALSE );
  736. break;
  737. } // switch
  738. return dwVal;
  739. } // AtqGetInfo()
  740. BOOL
  741. AtqGetStatistics(IN OUT ATQ_STATISTICS * pAtqStats)
  742. {
  743. if ( pAtqStats != NULL) {
  744. return g_pBandwidthInfo->GetStatistics( pAtqStats );
  745. } else {
  746. SetLastError( ERROR_INVALID_PARAMETER);
  747. return (FALSE);
  748. }
  749. } // AtqGetStatistics()
  750. BOOL
  751. AtqClearStatistics( VOID)
  752. {
  753. return g_pBandwidthInfo->ClearStatistics();
  754. } // AtqClearStatistics()
  755. ULONG_PTR
  756. AtqContextSetInfo(
  757. PATQ_CONTEXT patqContext,
  758. enum ATQ_CONTEXT_INFO atqInfo,
  759. ULONG_PTR Data
  760. )
  761. /*++
  762. Routine Description:
  763. Sets various bits of information for this context
  764. Arguments:
  765. patqContext - pointer to ATQ context
  766. atqInfo - Data item to set
  767. data - New value for item
  768. Return Value:
  769. The old value of the parameter
  770. --*/
  771. {
  772. PATQ_CONT pContext = (PATQ_CONT) patqContext;
  773. ULONG_PTR OldVal = 0;
  774. ATQ_ASSERT( pContext );
  775. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  776. if ( pContext && pContext->Signature == ATQ_CONTEXT_SIGNATURE )
  777. {
  778. switch ( atqInfo ) {
  779. case ATQ_INFO_TIMEOUT:
  780. OldVal = (ULONG_PTR)pContext->TimeOut;
  781. pContext->TimeOut = CanonTimeout( (DWORD)Data );
  782. break;
  783. case ATQ_INFO_RESUME_IO:
  784. //
  785. // set back the max timeout from pContext->TimeOut
  786. // This will ensure that timeout processing can go on
  787. // peacefully.
  788. //
  789. {
  790. DWORD currentTime = AtqGetCurrentTick( );
  791. DWORD timeout;
  792. OldVal = (ULONG_PTR)pContext->NextTimeout;
  793. timeout = pContext->TimeOut;
  794. //
  795. // Set the new timeout
  796. //
  797. I_SetNextTimeout(pContext);
  798. //
  799. // Return the old
  800. //
  801. if ( currentTime >= (DWORD)OldVal ) {
  802. ATQ_ASSERT((OldVal & ATQ_INFINITE) == 0);
  803. OldVal = 0;
  804. } else if ( (OldVal & ATQ_INFINITE) == 0 ) {
  805. OldVal -= currentTime;
  806. }
  807. // return correct units
  808. OldVal = (ULONG_PTR)UndoCanonTimeout( (DWORD)OldVal );
  809. }
  810. break;
  811. case ATQ_INFO_COMPLETION:
  812. OldVal = (ULONG_PTR)pContext->pfnCompletion;
  813. pContext->pfnCompletion = (ATQ_COMPLETION) Data;
  814. break;
  815. case ATQ_INFO_COMPLETION_CONTEXT:
  816. ATQ_ASSERT( Data != 0 ); // NULL context not allowed
  817. OldVal = (ULONG_PTR)pContext->ClientContext;
  818. pContext->ClientContext = (void *) Data;
  819. break;
  820. case ATQ_INFO_BANDWIDTH_INFO:
  821. {
  822. ATQ_ASSERT( Data != 0 );
  823. PBANDWIDTH_INFO pBandwidthInfo = (PBANDWIDTH_INFO) Data;
  824. ATQ_ASSERT( pBandwidthInfo->QuerySignature() ==
  825. ATQ_BW_INFO_SIGNATURE );
  826. if ( !pBandwidthInfo->IsFreed() )
  827. {
  828. pContext->m_pBandwidthInfo = (PBANDWIDTH_INFO) Data;
  829. pContext->m_pBandwidthInfo->Reference();
  830. }
  831. break;
  832. }
  833. case ATQ_INFO_ABORTIVE_CLOSE:
  834. OldVal = (ULONG_PTR)pContext->IsFlag( ACF_ABORTIVE_CLOSE );
  835. if ( Data )
  836. {
  837. pContext->SetFlag( ACF_ABORTIVE_CLOSE );
  838. }
  839. else
  840. {
  841. pContext->ResetFlag( ACF_ABORTIVE_CLOSE );
  842. }
  843. break;
  844. case ATQ_INFO_FORCE_CLOSE:
  845. OldVal = (ULONG_PTR)pContext->ForceClose();
  846. pContext->SetForceClose( Data ? TRUE : FALSE );
  847. break;
  848. case ATQ_INFO_SET_OVL_OFFSET:
  849. OldVal = 0;
  850. pContext->Overlapped.Offset = ((LARGE_INTEGER*)Data)->LowPart;
  851. pContext->Overlapped.OffsetHigh = ((LARGE_INTEGER*)Data)->HighPart;
  852. break;
  853. default:
  854. ATQ_ASSERT( FALSE );
  855. }
  856. }
  857. return OldVal;
  858. } // AtqContextSetInfo()
  859. BOOL
  860. AtqAddAsyncHandle(
  861. PATQ_CONTEXT * ppatqContext,
  862. PVOID EndpointObject,
  863. PVOID ClientContext,
  864. ATQ_COMPLETION pfnCompletion,
  865. DWORD TimeOut,
  866. HANDLE hAsyncIO
  867. )
  868. /*++
  869. Routine Description:
  870. Adds a handle to the thread queue
  871. The client should call this after the IO handle is opened
  872. and before the first IO request is made
  873. Even in the case of failure, client should call AtqFreeContext() and
  874. free the memory associated with this object.
  875. Arguments:
  876. ppatqContext - Receives allocated ATQ Context
  877. Context - Context to call client with
  878. pfnCompletion - Completion to call when IO completes
  879. TimeOut - Time to wait (sec) for IO completion (INFINITE is valid)
  880. hAsyncIO - Handle with pending read or write
  881. Return Value:
  882. TRUE if successful, FALSE on error (call GetLastError)
  883. --*/
  884. {
  885. return ( I_AtqAddAsyncHandle( (PATQ_CONT *) ppatqContext,
  886. (PATQ_ENDPOINT) EndpointObject,
  887. ClientContext,
  888. pfnCompletion,
  889. TimeOut,
  890. hAsyncIO)
  891. &&
  892. I_AddAtqContextToPort( *((PATQ_CONT *) ppatqContext))
  893. );
  894. } // AtqAddAsyncHandle()
  895. VOID
  896. AtqGetAcceptExAddrs(
  897. IN PATQ_CONTEXT patqContext,
  898. OUT SOCKET * pSock,
  899. OUT PVOID * ppvBuff,
  900. OUT PVOID * pEndpointContext,
  901. OUT SOCKADDR * * ppsockaddrLocal,
  902. OUT SOCKADDR * * ppsockaddrRemote
  903. )
  904. {
  905. PATQ_CONT pContext = (PATQ_CONT ) patqContext;
  906. INT cbsockaddrLocal;
  907. INT cbsockaddrRemote;
  908. DWORD cb;
  909. ATQ_ASSERT( g_fUseAcceptEx);
  910. ATQ_ASSERT( pContext->pEndpoint);
  911. *pSock = HANDLE_TO_SOCKET(pContext->hAsyncIO);
  912. *pEndpointContext = pContext->pEndpoint->Context;
  913. //
  914. // The buffer not only receives the initial received data, it also
  915. // gets the sock addrs, which must be at least sockaddr_in + 16 bytes
  916. // large
  917. //
  918. g_pfnGetAcceptExSockaddrs( pContext->pvBuff,
  919. (cb = pContext->pEndpoint->InitialRecvSize),
  920. MIN_SOCKADDR_SIZE,
  921. MIN_SOCKADDR_SIZE,
  922. ppsockaddrLocal,
  923. &cbsockaddrLocal,
  924. ppsockaddrRemote,
  925. &cbsockaddrRemote );
  926. *ppvBuff = ( ( cb == 0) ? NULL : pContext->pvBuff);
  927. return;
  928. } // AtqGetAcceptExAddrs()
  929. BOOL
  930. AtqCloseSocket(
  931. PATQ_CONTEXT patqContext,
  932. BOOL fShutdown
  933. )
  934. /*++
  935. Routine Description:
  936. Closes the socket in this atq structure if it wasn't
  937. closed by transmitfile. This function should be called only
  938. if the embedded handle in AtqContext is a Socket.
  939. Arguments:
  940. patqContext - Context whose socket should be closed.
  941. fShutdown - If TRUE, means we call shutdown and always close the socket.
  942. Note that if TransmitFile closed the socket, it will have done the
  943. shutdown for us
  944. Returns:
  945. TRUE on success and FALSE if there is a failure.
  946. --*/
  947. {
  948. PATQ_CONT pContext = (PATQ_CONT ) patqContext;
  949. if ( pContext ) {
  950. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  951. BOOL fAbortiveClose;
  952. fAbortiveClose = pContext->IsFlag( ACF_ABORTIVE_CLOSE );
  953. pContext->ResetFlag( ACF_ABORTIVE_CLOSE );
  954. //
  955. // Don't delete the socket if we don't have to
  956. //
  957. if ( pContext->IsState( ACS_SOCK_UNCONNECTED |
  958. ACS_SOCK_CLOSED) &&
  959. !pContext->ForceClose()
  960. ) {
  961. //
  962. // Do nothing
  963. //
  964. } else {
  965. // default:
  966. // case ACS_SOCK_LISTENING:
  967. // case ACS_SOCK_CONNECTED: {
  968. HANDLE hIO;
  969. PATQ_ENDPOINT pEndpoint;
  970. pEndpoint = pContext->pEndpoint;
  971. pContext->MoveState( ACS_SOCK_CLOSED);
  972. //
  973. // During shutdown, the socket may be closed while this thread
  974. // is doing processing, so only give a warning if any of the
  975. // following fail
  976. //
  977. hIO = (HANDLE )InterlockedExchangePointer(
  978. (PVOID *)&pContext->hAsyncIO,
  979. NULL
  980. );
  981. if ( hIO == NULL ) {
  982. //
  983. // No socket - it is already closed - do nothing.
  984. //
  985. } else {
  986. if (fAbortiveClose || fShutdown ) {
  987. //
  988. // If this is an AcceptEx socket, we must first force a
  989. // user mode context update before we can call shutdown
  990. //
  991. if ( (pEndpoint != NULL) && (pEndpoint->UseAcceptEx) ) {
  992. if ( setsockopt( HANDLE_TO_SOCKET(hIO),
  993. SOL_SOCKET,
  994. SO_UPDATE_ACCEPT_CONTEXT,
  995. (char *) &pEndpoint->ListenSocket,
  996. sizeof(SOCKET) ) == SOCKET_ERROR ) {
  997. ATQ_PRINTF(( DBG_CONTEXT,
  998. "[AtqCloseSocket] Warning- setsockopt "
  999. "failed, error %d, socket = %x,"
  1000. " Context= %08x, Listen = %lx\n",
  1001. GetLastError(),
  1002. hIO,
  1003. pContext,
  1004. pEndpoint->ListenSocket ));
  1005. }
  1006. }
  1007. } // setsock-opt call
  1008. if ( fAbortiveClose ) {
  1009. LINGER linger;
  1010. linger.l_onoff = TRUE;
  1011. linger.l_linger = 0;
  1012. if ( setsockopt( HANDLE_TO_SOCKET(hIO),
  1013. SOL_SOCKET,
  1014. SO_LINGER,
  1015. (char *) &linger,
  1016. sizeof(linger) ) == SOCKET_ERROR
  1017. ) {
  1018. ATQ_PRINTF(( DBG_CONTEXT,
  1019. "[AtqCloseSocket] Warning- setsockopt "
  1020. "failed, error %d, socket = %x,"
  1021. " Context= %08x, Listen = %lx\n",
  1022. GetLastError(),
  1023. hIO,
  1024. pContext,
  1025. pEndpoint->ListenSocket ));
  1026. }
  1027. else {
  1028. ATQ_PRINTF(( DBG_CONTEXT,
  1029. "[AtqCloseSocket(%08x)] requested"
  1030. " abortive close\n",
  1031. pContext));
  1032. }
  1033. } // set up linger
  1034. if ( fShutdown ) {
  1035. //
  1036. // Note that shutdown can fail in instances where the
  1037. // client aborts in the middle of a TransmitFile.
  1038. // This is an acceptable failure case
  1039. //
  1040. shutdown( HANDLE_TO_SOCKET(hIO), 1 );
  1041. }
  1042. DBG_ASSERT( hIO != NULL);
  1043. if ( closesocket( HANDLE_TO_SOCKET(hIO) ) ) {
  1044. ATQ_PRINTF(( DBG_CONTEXT,
  1045. "[AtqCloseSocket] Warning- closesocket "
  1046. " failed, Context = %08x, error %d,"
  1047. " socket = %x\n",
  1048. pContext,
  1049. GetLastError(),
  1050. hIO ));
  1051. }
  1052. } // if (hIO != NULL)
  1053. }
  1054. return TRUE;
  1055. }
  1056. DBGPRINTF(( DBG_CONTEXT, "[AtqCloseSocket] Warning - NULL Atq context\n"));
  1057. SetLastError( ERROR_INVALID_PARAMETER );
  1058. return FALSE;
  1059. } // AtqCloseSocket()
  1060. BOOL
  1061. AtqCloseFileHandle(
  1062. PATQ_CONTEXT patqContext
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. Closes the file handle in this atq structure.
  1067. This function should be called only if the embedded handle
  1068. in AtqContext is a file handle.
  1069. Arguments:
  1070. patqContext - Context whose file handle should be closed.
  1071. Returns:
  1072. TRUE on success and FALSE if there is a failure.
  1073. Note:
  1074. THIS FUNCTIONALITY IS ADDED TO SERVE A SPECIAL REQUEST!!!
  1075. Most of the ATQ code thinks that the handle here is a socket.
  1076. Except of course this function...
  1077. --*/
  1078. {
  1079. PATQ_CONT pContext = (PATQ_CONT ) patqContext;
  1080. if ( pContext != NULL ) {
  1081. HANDLE hIO;
  1082. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1083. ATQ_ASSERT( !pContext->IsAcceptExRootContext());
  1084. hIO =
  1085. (HANDLE ) InterlockedExchangePointer(
  1086. (PVOID *)&pContext->hAsyncIO,
  1087. NULL
  1088. );
  1089. if ( (hIO == NULL) || !CloseHandle( hIO ) ) {
  1090. ATQ_PRINTF(( DBG_CONTEXT,
  1091. "[AtqCloseFileHandle] Warning- CloseHandle failed, "
  1092. " Context = %08x, error %d, handle = %x\n",
  1093. pContext,
  1094. GetLastError(),
  1095. hIO ));
  1096. }
  1097. return TRUE;
  1098. }
  1099. DBGPRINTF(( DBG_CONTEXT, "[AtqCloseSocket] Warning - NULL Atq context\n"));
  1100. SetLastError( ERROR_INVALID_PARAMETER );
  1101. return FALSE;
  1102. } // AtqCloseFileHandle()
  1103. VOID
  1104. AtqFreeContext(
  1105. PATQ_CONTEXT patqContext,
  1106. BOOL fReuseContext
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. Frees the context created in AtqAddAsyncHandle.
  1111. Call this after the async handle has been closed and all outstanding
  1112. IO operations have been completed. The context is invalid after this call.
  1113. Call AtqFreeContext() for same context only ONCE.
  1114. Arguments:
  1115. patqContext - Context to free
  1116. fReuseContext - TRUE if this can context can be reused in the context of
  1117. the calling thread. Should be FALSE if the calling thread will exit
  1118. soon (i.e., isn't an AtqPoolThread).
  1119. --*/
  1120. {
  1121. PATQ_CONT pContext = (PATQ_CONT)patqContext;
  1122. ATQ_ASSERT( pContext != NULL );
  1123. IF_DEBUG( API_ENTRY) {
  1124. ATQ_PRINTF(( DBG_CONTEXT, "AtqFreeContext( %08x (handle=%08x,"
  1125. " nIOs = %d), fReuse=%d)\n",
  1126. patqContext, patqContext->hAsyncIO,
  1127. pContext->m_nIO,
  1128. fReuseContext));
  1129. }
  1130. if ( pContext ) {
  1131. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1132. if ( fReuseContext ) {
  1133. pContext->SetFlag( ACF_REUSE_CONTEXT);
  1134. } else {
  1135. pContext->ResetFlag( ACF_REUSE_CONTEXT);
  1136. }
  1137. if ( InterlockedDecrement( &pContext->m_nIO) == 0) {
  1138. //
  1139. // The number of outstanding ref holders is ZERO.
  1140. // Free up this ATQ context.
  1141. //
  1142. // We really do not free up the context - but try to reuse
  1143. // it if possible
  1144. //
  1145. DBG_ASSERT( pContext->lSyncTimeout == 0);
  1146. AtqpReuseOrFreeContext( pContext, fReuseContext);
  1147. }
  1148. }
  1149. return;
  1150. } // AtqFreeContext()
  1151. BOOL
  1152. AtqReadFile(
  1153. IN PATQ_CONTEXT patqContext,
  1154. IN LPVOID lpBuffer,
  1155. IN DWORD BytesToRead,
  1156. IN OVERLAPPED * lpo OPTIONAL
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. Does an async read using the handle defined in the context.
  1161. Arguments:
  1162. patqContext - pointer to ATQ context
  1163. lpBuffer - Buffer to put read data in
  1164. BytesToRead - number of bytes to read
  1165. lpo - Overlapped structure to use
  1166. Returns:
  1167. TRUE on success and FALSE if there is a failure.
  1168. --*/
  1169. {
  1170. BOOL fRes;
  1171. DWORD cbRead; // discarded after usage ( since this is Async)
  1172. PATQ_CONT pContext = (PATQ_CONT ) patqContext;
  1173. PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
  1174. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1175. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  1176. ATQ_ASSERT( pBandwidthInfo != NULL );
  1177. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  1178. InterlockedIncrement( &pContext->m_nIO);
  1179. I_SetNextTimeout(pContext);
  1180. pContext->BytesSent = 0;
  1181. if ( !lpo ) {
  1182. lpo = &pContext->Overlapped;
  1183. }
  1184. switch ( pBandwidthInfo->QueryStatus( AtqIoRead ) ) {
  1185. case StatusAllowOperation:
  1186. pBandwidthInfo->IncTotalAllowedRequests();
  1187. fRes = ( ReadFile( pContext->hAsyncIO,
  1188. lpBuffer,
  1189. BytesToRead,
  1190. &cbRead,
  1191. lpo ) ||
  1192. GetLastError() == ERROR_IO_PENDING);
  1193. if (!fRes) { InterlockedDecrement( &pContext->m_nIO); };
  1194. break;
  1195. case StatusBlockOperation:
  1196. // store data for restarting the operation.
  1197. pContext->arInfo.atqOp = AtqIoRead;
  1198. pContext->arInfo.lpOverlapped = lpo;
  1199. pContext->arInfo.uop.opReadWrite.buf1.len = BytesToRead;
  1200. pContext->arInfo.uop.opReadWrite.buf1.buf = (CHAR * ) lpBuffer;
  1201. pContext->arInfo.uop.opReadWrite.dwBufferCount = 1;
  1202. pContext->arInfo.uop.opReadWrite.pBufAll = NULL;
  1203. // Put this request in queue of blocked requests.
  1204. fRes = pBandwidthInfo->BlockRequest( pContext );
  1205. if ( fRes )
  1206. {
  1207. pBandwidthInfo->IncTotalBlockedRequests();
  1208. break;
  1209. }
  1210. // fall through
  1211. case StatusRejectOperation:
  1212. InterlockedDecrement( &pContext->m_nIO);
  1213. pBandwidthInfo->IncTotalRejectedRequests();
  1214. SetLastError( ERROR_NETWORK_BUSY);
  1215. fRes = FALSE;
  1216. break;
  1217. default:
  1218. ATQ_ASSERT( FALSE);
  1219. InterlockedDecrement( &pContext->m_nIO);
  1220. SetLastError( ERROR_INVALID_PARAMETER);
  1221. fRes = FALSE;
  1222. break;
  1223. } // switch()
  1224. return fRes;
  1225. } // AtqReadFile()
  1226. BOOL
  1227. AtqReadSocket(
  1228. IN PATQ_CONTEXT patqContext,
  1229. IN LPWSABUF pwsaBuffers,
  1230. IN DWORD dwBufferCount,
  1231. IN OVERLAPPED * lpo OPTIONAL
  1232. )
  1233. /*++
  1234. Routine Description:
  1235. Does an async recv using the handle defined in the context
  1236. as a socket.
  1237. Arguments:
  1238. patqContext - pointer to ATQ context
  1239. lpBuffer - Buffer to put read data in
  1240. BytesToRead - number of bytes to read
  1241. lpo - Overlapped structure to use
  1242. Returns:
  1243. TRUE on success and FALSE if there is a failure.
  1244. --*/
  1245. {
  1246. BOOL fRes;
  1247. DWORD cbRead; // discarded after usage ( since this is Async)
  1248. PATQ_CONT pContext = (PATQ_CONT ) patqContext;
  1249. PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
  1250. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1251. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  1252. ATQ_ASSERT( pBandwidthInfo != NULL );
  1253. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  1254. IF_DEBUG(API_ENTRY) {
  1255. ATQ_PRINTF(( DBG_CONTEXT,
  1256. "AtqReadSocket(%08lx) called.\n", pContext));
  1257. }
  1258. if (pContext->IsFlag( ACF_RECV_ISSUED)) {
  1259. pContext->BytesSent = 0;
  1260. pContext->SetFlag( ACF_RECV_CALLED);
  1261. #if CC_REF_TRACKING
  1262. //
  1263. // ATQ notification trace
  1264. //
  1265. // Notify client context of all non-oplock notification.
  1266. // This is for debugging purpose only.
  1267. //
  1268. // Code 0xf9f9f9f9 indicates a ACF_RECV_CALLED is set in the flags field
  1269. //
  1270. pContext->NotifyIOCompletion( (ULONG_PTR)pContext, pContext->m_acFlags, 0xf9f9f9f9 );
  1271. #endif
  1272. return TRUE;
  1273. }
  1274. I_SetNextTimeout(pContext);
  1275. // count the number of bytes
  1276. DBG_ASSERT( dwBufferCount >= 1);
  1277. pContext->BytesSent = 0;
  1278. InterlockedIncrement( &pContext->m_nIO);
  1279. if ( !lpo ) {
  1280. lpo = &pContext->Overlapped;
  1281. }
  1282. //
  1283. // NYI: Create an optimal function table
  1284. //
  1285. switch ( pBandwidthInfo->QueryStatus( AtqIoRead ) ) {
  1286. case StatusAllowOperation:
  1287. {
  1288. DWORD dwFlags = 0;
  1289. fRes = ( (WSARecv( HANDLE_TO_SOCKET(pContext->hAsyncIO),
  1290. pwsaBuffers,
  1291. dwBufferCount,
  1292. &cbRead,
  1293. &dwFlags, // no flags
  1294. lpo,
  1295. NULL // no completion routine
  1296. ) == 0) ||
  1297. (WSAGetLastError() == WSA_IO_PENDING));
  1298. if (!fRes) { InterlockedDecrement( &pContext->m_nIO); }
  1299. }
  1300. break;
  1301. case StatusBlockOperation:
  1302. // store data for restarting the operation.
  1303. pContext->arInfo.atqOp = AtqIoRead;
  1304. pContext->arInfo.lpOverlapped = lpo;
  1305. pContext->arInfo.uop.opReadWrite.dwBufferCount = dwBufferCount;
  1306. if ( dwBufferCount == 1) {
  1307. pContext->arInfo.uop.opReadWrite.buf1.len = pwsaBuffers->len;
  1308. pContext->arInfo.uop.opReadWrite.buf1.buf = pwsaBuffers->buf;
  1309. pContext->arInfo.uop.opReadWrite.pBufAll = NULL;
  1310. } else {
  1311. DBG_ASSERT( dwBufferCount > 1);
  1312. //
  1313. // Inefficient: But we will burn CPU for b/w throttling.
  1314. //
  1315. WSABUF * pBuf = (WSABUF *)
  1316. ::LocalAlloc( LPTR, dwBufferCount * sizeof (WSABUF));
  1317. if ( NULL != pBuf) {
  1318. pContext->arInfo.uop.opReadWrite.pBufAll = pBuf;
  1319. CopyMemory( pBuf, pwsaBuffers,
  1320. dwBufferCount * sizeof(WSABUF));
  1321. } else {
  1322. InterlockedDecrement( &pContext->m_nIO);
  1323. fRes = FALSE;
  1324. break;
  1325. }
  1326. }
  1327. // Put this request in queue of blocked requests.
  1328. fRes = pBandwidthInfo->BlockRequest( pContext );
  1329. if ( fRes )
  1330. {
  1331. pBandwidthInfo->IncTotalBlockedRequests();
  1332. break;
  1333. }
  1334. // fall through
  1335. case StatusRejectOperation:
  1336. InterlockedDecrement( &pContext->m_nIO);
  1337. pBandwidthInfo->IncTotalRejectedRequests();
  1338. SetLastError( ERROR_NETWORK_BUSY);
  1339. fRes = FALSE;
  1340. break;
  1341. default:
  1342. ATQ_ASSERT( FALSE);
  1343. InterlockedDecrement( &pContext->m_nIO);
  1344. SetLastError( ERROR_INVALID_PARAMETER);
  1345. fRes = FALSE;
  1346. break;
  1347. } // switch()
  1348. return fRes;
  1349. } // AtqReadSocket()
  1350. BOOL
  1351. AtqWriteFile(
  1352. IN PATQ_CONTEXT patqContext,
  1353. IN LPCVOID lpBuffer,
  1354. IN DWORD BytesToWrite,
  1355. IN OVERLAPPED * lpo OPTIONAL
  1356. )
  1357. /*++
  1358. Routine Description:
  1359. Does an async write using the handle defined in the context.
  1360. Arguments:
  1361. patqContext - pointer to ATQ context
  1362. lpBuffer - Buffer to write
  1363. BytesToWrite - number of bytes to write
  1364. lpo - Overlapped structure to use
  1365. Returns:
  1366. TRUE on success and FALSE if there is a failure.
  1367. --*/
  1368. {
  1369. BOOL fRes;
  1370. DWORD cbWritten; // discarded after usage ( since this is Async)
  1371. PATQ_CONT pContext = (PATQ_CONT ) patqContext;
  1372. PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
  1373. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1374. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  1375. ATQ_ASSERT( pBandwidthInfo != NULL );
  1376. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  1377. I_SetNextTimeout(pContext);
  1378. pContext->BytesSent = BytesToWrite;
  1379. if ( !lpo ) {
  1380. lpo = &pContext->Overlapped;
  1381. }
  1382. InterlockedIncrement( &pContext->m_nIO);
  1383. switch ( pBandwidthInfo->QueryStatus( AtqIoWrite) ) {
  1384. case StatusAllowOperation:
  1385. pBandwidthInfo->IncTotalAllowedRequests();
  1386. fRes = ( WriteFile( pContext->hAsyncIO,
  1387. lpBuffer,
  1388. BytesToWrite,
  1389. &cbWritten,
  1390. lpo ) ||
  1391. GetLastError() == ERROR_IO_PENDING);
  1392. if (!fRes) { InterlockedDecrement( &pContext->m_nIO); };
  1393. break;
  1394. case StatusBlockOperation:
  1395. // store data for restarting the operation.
  1396. pContext->arInfo.atqOp = AtqIoWrite;
  1397. pContext->arInfo.lpOverlapped = lpo;
  1398. pContext->arInfo.uop.opReadWrite.buf1.len = BytesToWrite;
  1399. pContext->arInfo.uop.opReadWrite.buf1.buf = (CHAR * ) lpBuffer;
  1400. pContext->arInfo.uop.opReadWrite.dwBufferCount = 1;
  1401. pContext->arInfo.uop.opReadWrite.pBufAll = NULL;
  1402. // Put this request in queue of blocked requests.
  1403. fRes = pBandwidthInfo->BlockRequest( pContext );
  1404. if ( fRes )
  1405. {
  1406. pBandwidthInfo->IncTotalBlockedRequests();
  1407. break;
  1408. }
  1409. // fall through
  1410. case StatusRejectOperation:
  1411. InterlockedDecrement( &pContext->m_nIO);
  1412. pBandwidthInfo->IncTotalRejectedRequests();
  1413. SetLastError( ERROR_NETWORK_BUSY);
  1414. fRes = FALSE;
  1415. break;
  1416. default:
  1417. ATQ_ASSERT( FALSE);
  1418. InterlockedDecrement( &pContext->m_nIO);
  1419. SetLastError( ERROR_INVALID_PARAMETER);
  1420. fRes = FALSE;
  1421. break;
  1422. } // switch()
  1423. return fRes;
  1424. } // AtqWriteFile()
  1425. BOOL
  1426. AtqWriteSocket(
  1427. IN PATQ_CONTEXT patqContext,
  1428. IN LPWSABUF pwsaBuffers,
  1429. IN DWORD dwBufferCount,
  1430. IN OVERLAPPED * lpo OPTIONAL
  1431. )
  1432. /*++
  1433. Routine Description:
  1434. Does an async write using the handle defined in the context as a socket.
  1435. Arguments:
  1436. patqContext - pointer to ATQ context
  1437. pwsaBuffer - pointer to Winsock Buffers for scatter/gather
  1438. dwBufferCount - DWORD containing the count of buffers pointed
  1439. to by pwsaBuffer
  1440. lpo - Overlapped structure to use
  1441. Returns:
  1442. TRUE on success and FALSE if there is a failure.
  1443. --*/
  1444. {
  1445. BOOL fRes;
  1446. DWORD cbWritten; // discarded after usage ( since this is Async)
  1447. PATQ_CONT pContext = (PATQ_CONT ) patqContext;
  1448. PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
  1449. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1450. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  1451. ATQ_ASSERT( pBandwidthInfo != NULL );
  1452. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  1453. I_SetNextTimeout(pContext);
  1454. //
  1455. // count the number of bytes
  1456. //
  1457. DBG_ASSERT( dwBufferCount >= 1);
  1458. pContext->BytesSent = pwsaBuffers->len;
  1459. if ( dwBufferCount > 1) {
  1460. LPWSABUF pWsaBuf;
  1461. for ( pWsaBuf = pwsaBuffers + 1;
  1462. pWsaBuf < (pwsaBuffers + dwBufferCount);
  1463. pWsaBuf++) {
  1464. pContext->BytesSent += pWsaBuf->len;
  1465. }
  1466. }
  1467. if ( lpo == NULL ) {
  1468. lpo = &pContext->Overlapped;
  1469. }
  1470. InterlockedIncrement( &pContext->m_nIO);
  1471. switch ( pBandwidthInfo->QueryStatus( AtqIoWrite ) ) {
  1472. case StatusAllowOperation:
  1473. pBandwidthInfo->IncTotalAllowedRequests();
  1474. fRes = ( (WSASend( HANDLE_TO_SOCKET(pContext->hAsyncIO),
  1475. pwsaBuffers,
  1476. dwBufferCount,
  1477. &cbWritten,
  1478. 0, // no flags
  1479. lpo,
  1480. NULL // no completion routine
  1481. ) == 0) ||
  1482. (WSAGetLastError() == WSA_IO_PENDING));
  1483. if (!fRes) { InterlockedDecrement( &pContext->m_nIO); }
  1484. break;
  1485. case StatusBlockOperation:
  1486. // store data for restarting the operation.
  1487. pContext->arInfo.atqOp = AtqIoWrite;
  1488. pContext->arInfo.lpOverlapped = lpo;
  1489. pContext->arInfo.uop.opReadWrite.dwBufferCount = dwBufferCount;
  1490. if ( dwBufferCount == 1) {
  1491. pContext->arInfo.uop.opReadWrite.buf1.len = pwsaBuffers->len;
  1492. pContext->arInfo.uop.opReadWrite.buf1.buf = pwsaBuffers->buf;
  1493. pContext->arInfo.uop.opReadWrite.pBufAll = NULL;
  1494. } else {
  1495. DBG_ASSERT( dwBufferCount > 1);
  1496. //
  1497. // Inefficient: But we will burn CPU for b/w throttling.
  1498. //
  1499. WSABUF * pBuf = (WSABUF *)
  1500. ::LocalAlloc( LPTR, dwBufferCount * sizeof (WSABUF));
  1501. if ( NULL != pBuf) {
  1502. pContext->arInfo.uop.opReadWrite.pBufAll = pBuf;
  1503. CopyMemory( pBuf, pwsaBuffers,
  1504. dwBufferCount * sizeof(WSABUF));
  1505. } else {
  1506. InterlockedDecrement( &pContext->m_nIO);
  1507. fRes = FALSE;
  1508. break;
  1509. }
  1510. }
  1511. // Put this request in queue of blocked requests.
  1512. fRes = pBandwidthInfo->BlockRequest( pContext );
  1513. if ( fRes )
  1514. {
  1515. pBandwidthInfo->IncTotalBlockedRequests();
  1516. break;
  1517. }
  1518. // fall through
  1519. case StatusRejectOperation:
  1520. InterlockedDecrement( &pContext->m_nIO);
  1521. pBandwidthInfo->IncTotalRejectedRequests();
  1522. SetLastError( ERROR_NETWORK_BUSY);
  1523. fRes = FALSE;
  1524. break;
  1525. default:
  1526. ATQ_ASSERT( FALSE);
  1527. InterlockedDecrement( &pContext->m_nIO);
  1528. SetLastError( ERROR_INVALID_PARAMETER);
  1529. fRes = FALSE;
  1530. break;
  1531. } // switch()
  1532. return fRes;
  1533. } // AtqWriteSocket()
  1534. BOOL
  1535. AtqSyncWsaSend(
  1536. IN PATQ_CONTEXT patqContext,
  1537. IN LPWSABUF pwsaBuffers,
  1538. IN DWORD dwBufferCount,
  1539. OUT LPDWORD pcbWritten
  1540. )
  1541. /*++
  1542. Routine Description:
  1543. Does a sync write of an array of wsa buffers using WSASend.
  1544. Arguments:
  1545. patqContext - pointer to ATQ context
  1546. pwsaBuffer - pointer to Winsock Buffers for scatter/gather
  1547. dwBufferCount - DWORD containing the count of buffers pointed
  1548. to by pwsaBuffer
  1549. pcbWritten - ptr to count of bytes written
  1550. Returns:
  1551. TRUE on success and FALSE if there is a failure.
  1552. --*/
  1553. {
  1554. BOOL fRes = FALSE;
  1555. PATQ_CONT pContext = (PATQ_CONT ) patqContext;
  1556. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1557. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  1558. fRes = ( WSASend( HANDLE_TO_SOCKET(pContext->hAsyncIO),
  1559. pwsaBuffers,
  1560. dwBufferCount,
  1561. pcbWritten,
  1562. 0, // no flags
  1563. NULL, // lpo == NULL for sync write
  1564. NULL // no completion routine
  1565. ) == 0);
  1566. return fRes;
  1567. } // AtqSyncWsaSend()
  1568. BOOL
  1569. AtqTransmitFile(
  1570. IN PATQ_CONTEXT patqContext,
  1571. IN HANDLE hFile,
  1572. IN DWORD dwBytesInFile,
  1573. IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
  1574. IN DWORD dwFlags
  1575. )
  1576. /*++
  1577. Routine Description:
  1578. Does a TransmitFile using the handle defined in the context.
  1579. Arguments:
  1580. patqContext - pointer to ATQ context
  1581. hFile - handle of file to read from
  1582. dwBytesInFile - Bytes to transmit
  1583. lpTransmitBuffers - transmit buffer structure
  1584. dwFlags - Transmit file flags
  1585. Returns:
  1586. TRUE on success and FALSE if there is a failure.
  1587. --*/
  1588. {
  1589. BOOL fRes;
  1590. PATQ_CONT pContext = (PATQ_CONT) patqContext;
  1591. PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
  1592. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1593. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  1594. ATQ_ASSERT( pBandwidthInfo != NULL );
  1595. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  1596. //
  1597. // For large file sends, the client's default timeout may not be
  1598. // adequte for slow links. Scale based on bytes being sent
  1599. //
  1600. I_SetNextTimeout(pContext);
  1601. pContext->BytesSent = dwBytesInFile;
  1602. if ( dwFlags == 0 ) {
  1603. //
  1604. // If no flags are set, then we can attempt to use the special
  1605. // write-behind flag. This flag can cause the TransmitFile to
  1606. // complete immediately, before the send actually completes.
  1607. // This can be a significant performance improvement inside the
  1608. // system.
  1609. //
  1610. dwFlags = TF_WRITE_BEHIND;
  1611. } else if ( dwFlags & TF_DISCONNECT ) {
  1612. //
  1613. // If the socket is getting disconnected, mark it appropriately
  1614. //
  1615. pContext->MoveState( ( ( dwFlags & TF_REUSE_SOCKET )?
  1616. ACS_SOCK_UNCONNECTED:
  1617. ACS_SOCK_CLOSED
  1618. )
  1619. );
  1620. }
  1621. //
  1622. // Use kernel apc flag unless configured not to
  1623. //
  1624. if ( g_fUseKernelApc ) {
  1625. dwFlags |= TF_USE_KERNEL_APC;
  1626. }
  1627. InterlockedIncrement( &pContext->m_nIO);
  1628. switch ( pBandwidthInfo->QueryStatus( AtqIoXmitFile ) ) {
  1629. case StatusAllowOperation:
  1630. pBandwidthInfo->IncTotalAllowedRequests();
  1631. fRes = (g_pfnTransmitFile( HANDLE_TO_SOCKET(pContext->hAsyncIO),
  1632. hFile,
  1633. dwBytesInFile,
  1634. 0,
  1635. &pContext->Overlapped,
  1636. lpTransmitBuffers,
  1637. dwFlags ) ||
  1638. (GetLastError() == ERROR_IO_PENDING));
  1639. if (!fRes) { InterlockedDecrement( &pContext->m_nIO); }
  1640. break;
  1641. case StatusBlockOperation:
  1642. // store data for restarting the operation.
  1643. pContext->arInfo.atqOp = AtqIoXmitFile;
  1644. pContext->arInfo.lpOverlapped = &pContext->Overlapped;
  1645. pContext->arInfo.uop.opXmit.hFile = hFile;
  1646. pContext->arInfo.uop.opXmit.dwBytesInFile = dwBytesInFile;
  1647. pContext->arInfo.uop.opXmit.lpXmitBuffers = lpTransmitBuffers;
  1648. pContext->arInfo.uop.opXmit.dwFlags = dwFlags;
  1649. // Put this request in queue of blocked requests.
  1650. fRes = pBandwidthInfo->BlockRequest( pContext);
  1651. if ( fRes )
  1652. {
  1653. pBandwidthInfo->IncTotalBlockedRequests();
  1654. break;
  1655. }
  1656. // fall through
  1657. case StatusRejectOperation:
  1658. InterlockedDecrement( &pContext->m_nIO);
  1659. pBandwidthInfo->IncTotalRejectedRequests();
  1660. SetLastError( ERROR_NETWORK_BUSY);
  1661. fRes = FALSE;
  1662. break;
  1663. default:
  1664. ATQ_ASSERT( FALSE);
  1665. InterlockedDecrement( &pContext->m_nIO);
  1666. SetLastError( ERROR_INVALID_PARAMETER);
  1667. fRes = FALSE;
  1668. break;
  1669. } // switch()
  1670. //
  1671. // Restore the socket state if we failed so that the handle gets freed
  1672. //
  1673. if ( !fRes )
  1674. {
  1675. pContext->MoveState( ACS_SOCK_CONNECTED);
  1676. }
  1677. return fRes;
  1678. } // AtqTransmitFile()
  1679. BOOL
  1680. AtqTransmitFileEx(
  1681. IN PATQ_CONTEXT patqContext,
  1682. IN HANDLE hFile,
  1683. IN DWORD dwBytesInFile,
  1684. IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
  1685. IN DWORD dwFlags,
  1686. IN OVERLAPPED * lpo
  1687. )
  1688. /*++
  1689. Routine Description:
  1690. Does a TransmitFile using the handle defined in the context.
  1691. Uses the parameter lpo instead of the structure in the context.
  1692. Arguments:
  1693. patqContext - pointer to ATQ context
  1694. hFile - handle of file to read from
  1695. dwBytesInFile - Bytes to transmit
  1696. lpTransmitBuffers - transmit buffer structure
  1697. dwFlags - Transmit file flags
  1698. lpo - overlapped structure
  1699. Returns:
  1700. TRUE on success and FALSE if there is a failure.
  1701. --*/
  1702. {
  1703. BOOL fRes = TRUE;
  1704. PATQ_CONT pContext = (PATQ_CONT) patqContext;
  1705. PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
  1706. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1707. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  1708. ATQ_ASSERT( pBandwidthInfo != NULL );
  1709. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  1710. //
  1711. // For large file sends, the client's default timeout may not be
  1712. // adequte for slow links. Scale based on bytes being sent
  1713. //
  1714. I_SetNextTimeout(pContext);
  1715. pContext->BytesSent = dwBytesInFile;
  1716. if ( dwFlags == 0 ) {
  1717. //
  1718. // If no flags are set, then we can attempt to use the special
  1719. // write-behind flag. This flag can cause the TransmitFile to
  1720. // complete immediately, before the send actually completes.
  1721. // This can be a significant performance improvement inside the
  1722. // system.
  1723. //
  1724. dwFlags = TF_WRITE_BEHIND;
  1725. } else if ( dwFlags & TF_DISCONNECT ) {
  1726. //
  1727. // If the socket is getting disconnected, mark it appropriately
  1728. //
  1729. pContext->MoveState( ( ( dwFlags & TF_REUSE_SOCKET )?
  1730. ACS_SOCK_UNCONNECTED:
  1731. ACS_SOCK_CLOSED
  1732. )
  1733. );
  1734. }
  1735. InterlockedIncrement( &pContext->m_nIO);
  1736. if ( (StatusAllowOperation == pBandwidthInfo->QueryStatus( AtqIoXmitFile ) ) ) {
  1737. pBandwidthInfo->IncTotalAllowedRequests();
  1738. fRes = (g_pfnTransmitFile( HANDLE_TO_SOCKET(pContext->hAsyncIO),
  1739. hFile,
  1740. dwBytesInFile,
  1741. 0,
  1742. (lpo == NULL) ? &pContext->Overlapped : lpo,
  1743. lpTransmitBuffers,
  1744. dwFlags ) ||
  1745. (GetLastError() == ERROR_IO_PENDING));
  1746. if (!fRes) { InterlockedDecrement( &pContext->m_nIO); };
  1747. } else {
  1748. ASSERT(FALSE);
  1749. fRes = FALSE;
  1750. }
  1751. //
  1752. // Restore the socket state if we failed so that the handle gets freed
  1753. //
  1754. if ( !fRes )
  1755. {
  1756. pContext->MoveState( ACS_SOCK_CONNECTED);
  1757. }
  1758. return fRes;
  1759. } // AtqTransmitFileEx()
  1760. BOOL
  1761. AtqReadDirChanges(IN PATQ_CONTEXT patqContext,
  1762. IN LPVOID lpBuffer,
  1763. IN DWORD BytesToRead,
  1764. IN BOOL fWatchSubDir,
  1765. IN DWORD dwNotifyFilter,
  1766. IN OVERLAPPED * lpo
  1767. )
  1768. /*++
  1769. AtqReadDirChanges()
  1770. Description:
  1771. This function submits an Async ReadDirectoryChanges() call for
  1772. the Async handle in the ATQ context supplied.
  1773. It always requires a non-NULL overlapped pointer for processing
  1774. this call.
  1775. Arguments:
  1776. patqContext - pointer to ATQ Context
  1777. lpBuffer - buffer for the data to be read from ReadDirectoryChanges()
  1778. BytesToRead - count of bytes to read into buffer
  1779. fWatchSubDir - should we watch for sub directory changes
  1780. dwNotifyFilter - DWORD containing the flags for Notification
  1781. lpo - pointer to overlapped structure.
  1782. Returns:
  1783. TRUE if ReadDirectoryChanges() is successfully submitted.
  1784. FALSE if there is any failure in submitting IO.
  1785. --*/
  1786. {
  1787. BOOL fRes;
  1788. DWORD cbRead; // discarded after usage ( since this is Async)
  1789. PATQ_CONT pContext = (PATQ_CONT ) patqContext;
  1790. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  1791. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  1792. if ( g_pfnReadDirChangesW == NULL ) {
  1793. ATQ_PRINTF((DBG_CONTEXT,"ReadDirChanges entry point NULL\n"));
  1794. SetLastError(ERROR_NOT_SUPPORTED);
  1795. return(FALSE);
  1796. }
  1797. if ( lpo == NULL ) {
  1798. SetLastError(ERROR_INVALID_PARAMETER);
  1799. return FALSE;
  1800. }
  1801. I_SetNextTimeout(pContext);
  1802. pContext->BytesSent = 0;
  1803. InterlockedIncrement( &pContext->m_nIO);
  1804. fRes = g_pfnReadDirChangesW( pContext->hAsyncIO,
  1805. lpBuffer,
  1806. BytesToRead,
  1807. fWatchSubDir,
  1808. dwNotifyFilter,
  1809. &cbRead,
  1810. lpo,
  1811. NULL);
  1812. if (!fRes) { InterlockedDecrement( &pContext->m_nIO); };
  1813. return fRes;
  1814. } // AtqReadDirChanges()
  1815. BOOL
  1816. AtqPostCompletionStatus(
  1817. IN PATQ_CONTEXT patqContext,
  1818. IN DWORD BytesTransferred
  1819. )
  1820. /*++
  1821. Routine Description:
  1822. Posts a completion status on the completion port queue
  1823. An IO pending error code is treated as a success error code
  1824. Arguments:
  1825. patqContext - pointer to ATQ context
  1826. Everything else as in the Win32 API
  1827. NOTES:
  1828. Return Value:
  1829. TRUE if successful, FALSE on error (call GetLastError)
  1830. --*/
  1831. {
  1832. BOOL fRes;
  1833. PATQ_CONT pAtqContext = (PATQ_CONT ) patqContext;
  1834. PBANDWIDTH_INFO pBandwidthInfo = pAtqContext->m_pBandwidthInfo;
  1835. ATQ_ASSERT( (pAtqContext)->Signature == ATQ_CONTEXT_SIGNATURE );
  1836. ATQ_ASSERT( pBandwidthInfo != NULL );
  1837. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  1838. if ( !pAtqContext->IsBlocked()) {
  1839. InterlockedIncrement( &pAtqContext->m_nIO);
  1840. fRes = ( g_pfnPostCompletionStatus( g_hCompPort,
  1841. BytesTransferred,
  1842. (ULONG_PTR)patqContext,
  1843. &pAtqContext->Overlapped ) ||
  1844. (GetLastError() == ERROR_IO_PENDING));
  1845. if (!fRes) { InterlockedDecrement( &pAtqContext->m_nIO); };
  1846. } else {
  1847. //
  1848. // Forcibly remove the context from blocking list.
  1849. //
  1850. fRes = pBandwidthInfo->RemoveFromBlockedList(pAtqContext);
  1851. // There is a possibility of race conditions!
  1852. // If we cant remove an item from blocking list before
  1853. // its IO operation is scheduled.
  1854. // there wont be any call back generated for this case!
  1855. }
  1856. return fRes;
  1857. } // AtqPostCompletionStatus
  1858. DWORD
  1859. I_AtqGetGlobalConfiguration(VOID)
  1860. /*++
  1861. Description:
  1862. This function sets several global config params for the ATQ package.
  1863. It also reads the global configuration from registry for ATQ.
  1864. The values if present will override the defaults
  1865. Returns:
  1866. Win32 Errorcode - NO_ERROR on success and anything else for error
  1867. --*/
  1868. {
  1869. DWORD dwError = NO_ERROR;
  1870. DWORD dwDefaultThreadTimeout = ATQ_REG_DEF_THREAD_TIMEOUT;
  1871. //
  1872. // If this is a NTW, do the right thing
  1873. //
  1874. if ( !TsIsNtServer() ) {
  1875. g_cMaxThreadLimit = ATQ_REG_MIN_POOL_THREAD_LIMIT;
  1876. } else {
  1877. MEMORYSTATUS ms;
  1878. //
  1879. // get the memory size
  1880. //
  1881. ms.dwLength = sizeof(MEMORYSTATUS);
  1882. GlobalMemoryStatus( &ms );
  1883. //
  1884. // Alloc two threads per MB of memory.
  1885. //
  1886. g_cMaxThreadLimit = (LONG)((ms.dwTotalPhys >> 19) + 2);
  1887. if ( g_cMaxThreadLimit < ATQ_REG_MIN_POOL_THREAD_LIMIT ) {
  1888. g_cMaxThreadLimit = ATQ_REG_MIN_POOL_THREAD_LIMIT;
  1889. } else if ( g_cMaxThreadLimit > ATQ_REG_MAX_POOL_THREAD_LIMIT ) {
  1890. g_cMaxThreadLimit = ATQ_REG_MAX_POOL_THREAD_LIMIT;
  1891. }
  1892. }
  1893. //
  1894. // Get entry points for NT
  1895. //
  1896. if ( !I_AtqInitializeNtEntryPoints( ) ) {
  1897. dwError = ERROR_MOD_NOT_FOUND;
  1898. return ( dwError);
  1899. }
  1900. g_pfnCreateCompletionPort = CreateIoCompletionPort;
  1901. g_pfnGetQueuedCompletionStatus = GetQueuedCompletionStatus;
  1902. g_pfnCloseCompletionPort = CloseHandle;
  1903. g_pfnPostCompletionStatus = PostQueuedCompletionStatus;
  1904. HKEY hkey = NULL;
  1905. DWORD dwVal;
  1906. dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1907. g_PSZ_ATQ_CONFIG_PARAMS_REG_KEY,
  1908. 0,
  1909. KEY_READ,
  1910. &hkey);
  1911. if ( dwError == NO_ERROR ) {
  1912. //
  1913. // Read the Concurrency factor per processor
  1914. //
  1915. dwVal = I_AtqReadRegDword( hkey,
  1916. ATQ_REG_PER_PROCESSOR_CONCURRENCY,
  1917. ATQ_REG_DEF_PER_PROCESSOR_CONCURRENCY);
  1918. AtqSetInfo( AtqMaxConcurrency, (ULONG_PTR)dwVal);
  1919. //
  1920. // Read the count of threads to be allowed per processor
  1921. //
  1922. dwVal = I_AtqReadRegDword( hkey,
  1923. ATQ_REG_PER_PROCESSOR_ATQ_THREADS,
  1924. ATQ_REG_DEF_PER_PROCESSOR_ATQ_THREADS
  1925. );
  1926. if ( dwVal != 0 ) {
  1927. AtqSetInfo( AtqMaxPoolThreads, (ULONG_PTR)dwVal);
  1928. }
  1929. //
  1930. // Read the Data transfer rate value for our calculations
  1931. //
  1932. dwVal = I_AtqReadRegDword( hkey,
  1933. ATQ_REG_MIN_KB_SEC,
  1934. ATQ_REG_DEF_MIN_KB_SEC );
  1935. AtqSetInfo( AtqMinKbSec, (ULONG_PTR)dwVal);
  1936. //
  1937. // read the max thread limit
  1938. //
  1939. g_cMaxThreadLimit = I_AtqReadRegDword( hkey,
  1940. ATQ_REG_POOL_THREAD_LIMIT,
  1941. g_cMaxThreadLimit);
  1942. //
  1943. // read the listen backlog
  1944. //
  1945. g_cListenBacklog = I_AtqReadRegDword( hkey,
  1946. ATQ_REG_LISTEN_BACKLOG,
  1947. g_cListenBacklog);
  1948. //
  1949. // Read the time (in seconds) of how long the threads
  1950. // can stay alive when there is no IO operation happening on
  1951. // that thread.
  1952. //
  1953. dwVal = I_AtqReadRegDword( hkey,
  1954. ATQ_REG_THREAD_TIMEOUT,
  1955. dwDefaultThreadTimeout
  1956. );
  1957. AtqSetInfo( AtqThreadTimeout, (ULONG_PTR)dwVal);
  1958. //
  1959. // See if we need to turn off TF_USE_KERNEL_APC flag for
  1960. // TransmitFile
  1961. //
  1962. dwVal = I_AtqReadRegDword( hkey,
  1963. ATQ_REG_USE_KERNEL_APC,
  1964. ATQ_REG_DEF_USE_KERNEL_APC );
  1965. g_fUseKernelApc = dwVal;
  1966. //
  1967. // Whether or not to enable debug thread creator
  1968. //
  1969. dwVal = I_AtqReadRegDword( hkey,
  1970. ATQ_REG_ENABLE_DEBUG_THREADS,
  1971. g_fEnableDebugThreads );
  1972. g_fEnableDebugThreads = !!dwVal;
  1973. //
  1974. // Do we want to run this backlog monitor at all?
  1975. //
  1976. dwVal = I_AtqReadRegDword( hkey,
  1977. ATQ_REG_DISABLE_BACKLOG_MONITOR,
  1978. g_fDisableBacklogMonitor );
  1979. g_fDisableBacklogMonitor = !!dwVal;
  1980. //
  1981. // Read timeout for backlog monitor
  1982. //
  1983. dwVal = I_AtqReadRegDword( hkey,
  1984. ATQ_REG_FORCE_TIMEOUT,
  1985. g_cForceTimeout );
  1986. g_cForceTimeout = dwVal;
  1987. ATQ_REQUIRE( !RegCloseKey( hkey ) );
  1988. hkey = NULL;
  1989. }
  1990. DBG_ASSERT( NULL == hkey);
  1991. return ( dwError);
  1992. } // I_AtqGetGlobalConfiguration()
  1993. DWORD
  1994. I_NumAtqEndpointsOpen(VOID)
  1995. /*++
  1996. Description:
  1997. This function counts the number of Enpoints that remain open.
  1998. Arguments:
  1999. None
  2000. Returns:
  2001. DWORD containing the number of endpoints that are open.
  2002. --*/
  2003. {
  2004. DWORD nEPOpen = 0;
  2005. AcquireLock( &AtqEndpointLock);
  2006. PLIST_ENTRY plEP;
  2007. for( plEP = AtqEndpointList.Flink;
  2008. plEP != &AtqEndpointList;
  2009. plEP = plEP->Flink ) {
  2010. nEPOpen++;
  2011. } // for
  2012. ReleaseLock( &AtqEndpointLock);
  2013. return ( nEPOpen);
  2014. } // I_NumAtqEndpointsOpen()
  2015. //
  2016. // Global functions
  2017. //
  2018. DWORD
  2019. I_AtqReadRegDword(
  2020. IN HKEY hkey,
  2021. IN LPCSTR pszValueName,
  2022. IN DWORD dwDefaultValue )
  2023. /*++
  2024. NAME: I_AtqReadRegDword
  2025. SYNOPSIS: Reads a DWORD value from the registry.
  2026. ENTRY: hkey - Openned registry key to read
  2027. pszValueName - The name of the value.
  2028. dwDefaultValue - The default value to use if the
  2029. value cannot be read.
  2030. RETURNS DWORD - The value from the registry, or dwDefaultValue.
  2031. --*/
  2032. {
  2033. DWORD err;
  2034. DWORD dwBuffer;
  2035. DWORD cbBuffer = sizeof(dwBuffer);
  2036. DWORD dwType;
  2037. if( hkey != NULL ) {
  2038. err = RegQueryValueExA( hkey,
  2039. pszValueName,
  2040. NULL,
  2041. &dwType,
  2042. (LPBYTE)&dwBuffer,
  2043. &cbBuffer );
  2044. if( ( err == NO_ERROR ) && ( dwType == REG_DWORD ) ) {
  2045. dwDefaultValue = dwBuffer;
  2046. }
  2047. }
  2048. return dwDefaultValue;
  2049. } // I_AtqReadRegDword()
  2050. BOOL
  2051. AtqSetSocketOption(
  2052. IN PATQ_CONTEXT patqContext,
  2053. IN INT optName,
  2054. IN INT optValue
  2055. )
  2056. /*++
  2057. AtqSetSocketOption()
  2058. Routine Description:
  2059. Set socket options. Presently only handles TCP_NODELAY
  2060. Arguments:
  2061. patqContext - pointer to ATQ context
  2062. optName - name of property to change
  2063. optValue - value of property to set
  2064. Return Value:
  2065. TRUE if successful, else FALSE
  2066. --*/
  2067. {
  2068. if (TCP_NODELAY != optName)
  2069. {
  2070. return FALSE;
  2071. }
  2072. PATQ_CONT pContext = (PATQ_CONT)patqContext;
  2073. ATQ_ASSERT( pContext != NULL );
  2074. IF_DEBUG( API_ENTRY) {
  2075. ATQ_PRINTF(( DBG_CONTEXT, "AtqSetSocketOption( %08x (handle=%08x,"
  2076. " nIOs = %d), optName=%d, optValue=%d)\n",
  2077. patqContext, patqContext->hAsyncIO,
  2078. pContext->m_nIO, optName, optValue));
  2079. }
  2080. if ( pContext ) {
  2081. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  2082. if ( ((BOOL)pContext->IsFlag(ACF_TCP_NODELAY)) == ((BOOL)optValue))
  2083. {
  2084. //
  2085. // The flag is already enabled. Return success.
  2086. //
  2087. return TRUE;
  2088. }
  2089. else
  2090. {
  2091. if (NO_ERROR == setsockopt( HANDLE_TO_SOCKET(pContext->hAsyncIO),
  2092. IPPROTO_TCP,
  2093. TCP_NODELAY,
  2094. (char *)&optValue,
  2095. sizeof(INT)))
  2096. {
  2097. if ( optValue)
  2098. {
  2099. pContext->SetFlag(ACF_TCP_NODELAY);
  2100. }
  2101. else
  2102. {
  2103. pContext->ResetFlag(ACF_TCP_NODELAY);
  2104. }
  2105. return TRUE;
  2106. }
  2107. }
  2108. }
  2109. return FALSE;
  2110. }
  2111. PIIS_CAP_TRACE_INFO
  2112. AtqGetCapTraceInfo(
  2113. IN PATQ_CONTEXT patqContext
  2114. )
  2115. {
  2116. PATQ_CONT pContext = (PATQ_CONT)patqContext;
  2117. ATQ_ASSERT( pContext != NULL );
  2118. return pContext->GetCapTraceInfo();
  2119. }
  2120. DWORD
  2121. AtqDebugCreatorThread(
  2122. LPDWORD param
  2123. )
  2124. /*++
  2125. Routine Description:
  2126. For debugging purpose.
  2127. This function will cause another IO thread to be created (regardless of
  2128. the max thread limit). This IO thread will only serve new connections.
  2129. To trigger the creation of a new thread, set isatq!g_fCreateDebugThread=1
  2130. Arguments:
  2131. param - Unused
  2132. Return Value:
  2133. ERROR_SUCCESS
  2134. --*/
  2135. {
  2136. for ( ; !g_fShutdown ; )
  2137. {
  2138. Sleep( 5000 );
  2139. if ( g_fCreateDebugThread )
  2140. {
  2141. OutputDebugString( "Creating DEBUG thread." \
  2142. "Reseting isatq!g_fCreateDebugThread\n" );
  2143. I_AtqCheckThreadStatus( (VOID*) ATQ_DEBUG_THREAD );
  2144. g_fCreateDebugThread = FALSE;
  2145. }
  2146. }
  2147. return ERROR_SUCCESS;
  2148. }
  2149. /************************ End of File ***********************/