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.

689 lines
18 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\routing\ipx\sap\sapmain.c
  5. Abstract:
  6. SAP DLL main module and thread container.
  7. Author:
  8. Vadim Eydelman 05-15-1995
  9. Revision History:
  10. --*/
  11. #include "sapp.h"
  12. // Time limit for shutdown broadcast
  13. ULONG ShutdownTimeout=SAP_SHUTDOWN_TIMEOUT_DEF;
  14. // Indeces of synchronization objects used to control asynchronous
  15. // subsystems of SAP agent
  16. // Main thread signalling event
  17. #define STOP_EVENT_IDX 0
  18. #define RECV_COMPLETED_IDX (STOP_EVENT_IDX+1)
  19. // Timer queue requires attention
  20. #define TIMER_WAKEUP_IDX (RECV_COMPLETED_IDX+1)
  21. // Server table aging queue requires processing
  22. #define SERVER_TABLE_TIMER_IDX (TIMER_WAKEUP_IDX+1)
  23. // Server table sorted list requires update
  24. #define SERVER_TABLE_UPDATE_IDX (SERVER_TABLE_TIMER_IDX+1)
  25. // Adapter change signalled by network driver (for standalone SAP only)
  26. #define ADAPTER_CHG_IDX (SERVER_TABLE_UPDATE_IDX+1)
  27. // Number of syncronization objects
  28. #define ROUTING_NUM_OF_OBJECTS (SERVER_TABLE_UPDATE_IDX+1)
  29. #define STANDALONE_NUM_OF_OBJECTS (ADAPTER_CHG_IDX+1)
  30. #define MAX_OBJECTS STANDALONE_NUM_OF_OBJECTS
  31. /* Global Data */
  32. // DLL module instance handle
  33. HANDLE hDLLInstance;
  34. // Handle of main thread
  35. HANDLE MainThreadHdl;
  36. // Operational state of the agent
  37. ULONG OperationalState=OPER_STATE_DOWN;
  38. // Lock that protects changes in the state and state transitions
  39. CRITICAL_SECTION OperationalStateLock;
  40. // TRUE between start and stop service calls
  41. volatile BOOLEAN ServiceIfActive=FALSE;
  42. // TRUE between start and stop protocol calls
  43. volatile BOOLEAN RouterIfActive=FALSE;
  44. // TRUE if sap is part of the router, FALSE for standalone SAP agent
  45. // It is computed based on two values above with RouterIfActive having
  46. // precedence. In stays where it was during transition periods and changes
  47. // only when transition is completed (it can only be changed by the main
  48. // thread).
  49. volatile BOOLEAN Routing=FALSE;
  50. /* Local static data */
  51. // Async subsystem synchronization objects
  52. HANDLE WaitObjects[MAX_OBJECTS] = {NULL};
  53. // Time we will die at when told to shutdown
  54. ULONG StopTime;
  55. TCHAR ModuleName[MAX_PATH+1];
  56. // Local prototypes
  57. BOOL WINAPI DllMain(
  58. HINSTANCE hinstDLL,
  59. DWORD fdwReason,
  60. LPVOID lpvReserved
  61. );
  62. DWORD WINAPI
  63. MainThread (
  64. LPVOID param
  65. );
  66. VOID
  67. ReadRegistry (
  68. VOID
  69. );
  70. VOID
  71. InitializeResultQueue();
  72. /*++
  73. *******************************************************************
  74. D l l M a i n
  75. Routine Description:
  76. Dll entry point to be called from CRTstartup dll entry point (it
  77. will be actually an entry point for this dll)
  78. Arguments:
  79. hinstDLL - handle of DLL module
  80. fdwReason - reason for calling function
  81. lpvReserved - reserved
  82. Return Value:
  83. TRUE - process initialization was performed OK
  84. FALSE - intialization failed
  85. *******************************************************************
  86. --*/
  87. BOOL WINAPI DllMain(
  88. HINSTANCE hinstDLL,
  89. DWORD fdwReason,
  90. LPVOID lpvReserved
  91. ) {
  92. STARTUPINFO info;
  93. switch (fdwReason) {
  94. case DLL_PROCESS_ATTACH: // We are being attached to a new process
  95. hDLLInstance = hinstDLL;
  96. GetModuleFileName (hinstDLL, ModuleName,
  97. sizeof (ModuleName)/sizeof (ModuleName[0]));
  98. InitializeCriticalSection (&OperationalStateLock);
  99. InitializeResultQueue();
  100. return TRUE;
  101. case DLL_PROCESS_DETACH: // The process is exiting
  102. ASSERT (OperationalState==OPER_STATE_DOWN);
  103. DeleteCriticalSection (&OperationalStateLock);
  104. default: // Not interested in all other cases
  105. return TRUE;
  106. }
  107. }
  108. /*++
  109. *******************************************************************
  110. C r e a t e A l l C o m p o n e n t s
  111. Routine Description:
  112. Calls all sap componenets with initialization call and compiles an
  113. array of synchronization objects from objects returned from each
  114. individual component
  115. Arguments:
  116. None
  117. Return Value:
  118. NO_ERROR - component initialization was performed OK
  119. other - operation failed (windows error code)
  120. *******************************************************************
  121. --*/
  122. DWORD
  123. CreateAllComponents (
  124. HANDLE RMNotificationEvent
  125. ) {
  126. DWORD status;
  127. DbgInitialize (hDLLInstance);
  128. ReadRegistry ();
  129. status = CreateServerTable (
  130. &WaitObjects[SERVER_TABLE_UPDATE_IDX],
  131. &WaitObjects[SERVER_TABLE_TIMER_IDX]);
  132. if (status==NO_ERROR) {
  133. status = IpxSapCreateTimerQueue (&WaitObjects[TIMER_WAKEUP_IDX]);
  134. if (status==NO_ERROR) {
  135. status = CreateInterfaceTable ();
  136. if (status==NO_ERROR) {
  137. status = CreateIOQueue (&WaitObjects[RECV_COMPLETED_IDX]);
  138. if (status==NO_ERROR) {
  139. status = InitializeLPCStuff ();
  140. if (status==NO_ERROR) {
  141. status = CreateFilterTable ();
  142. if (status==NO_ERROR) {
  143. status = InitializeWorkers (WaitObjects[RECV_COMPLETED_IDX]);
  144. if (status==NO_ERROR) {
  145. WaitObjects[STOP_EVENT_IDX] =
  146. CreateEvent (NULL,
  147. FALSE, //Autoreset
  148. FALSE, // non-signalled
  149. NULL);
  150. if (WaitObjects[STOP_EVENT_IDX]!=NULL) {
  151. if (RMNotificationEvent == NULL)
  152. status = CreateAdapterPort (&WaitObjects[ADAPTER_CHG_IDX]);
  153. else
  154. status = CreateResultQueue (RMNotificationEvent);
  155. if (status==NO_ERROR)
  156. return NO_ERROR;
  157. }
  158. else {
  159. status = GetLastError ();
  160. Trace (DEBUG_FAILURES, "File: %s, line %ld."
  161. " Could not create stop event (gle:%ld).",
  162. __FILE__, __LINE__, status);
  163. }
  164. DeleteWorkers ();
  165. }
  166. DeleteFilterTable ();
  167. }
  168. DeleteLPCStuff();
  169. }
  170. DeleteIOQueue ();
  171. }
  172. DeleteInterfaceTable ();
  173. }
  174. IpxSapDeleteTimerQueue ();
  175. }
  176. DeleteServerTable ();
  177. }
  178. return status;
  179. }
  180. /*++
  181. *******************************************************************
  182. D e l e t e A l l C o m p o n e n t s
  183. Routine Description:
  184. Releases all resources allocated by SAP agent
  185. Arguments:
  186. None
  187. Return Value:
  188. NO_ERROR - SAP agent was unloaded OK
  189. other - operation failed (windows error code)
  190. *******************************************************************
  191. --*/
  192. DWORD
  193. DeleteAllComponents (
  194. void
  195. ) {
  196. UINT i;
  197. DWORD status;
  198. EnterCriticalSection (&OperationalStateLock);
  199. OperationalState = OPER_STATE_DOWN;
  200. LeaveCriticalSection (&OperationalStateLock);
  201. // Stop now
  202. StopTime = GetTickCount ();
  203. CloseHandle (WaitObjects[STOP_EVENT_IDX]);
  204. DeleteFilterTable ();
  205. DeleteLPCStuff ();
  206. DeleteIOQueue ();
  207. DeleteInterfaceTable ();
  208. IpxSapDeleteTimerQueue ();
  209. DeleteServerTable ();
  210. DeleteWorkers ();
  211. DbgStop ();
  212. return NO_ERROR;
  213. }
  214. /*++
  215. *******************************************************************
  216. S t a r t S A P
  217. Routine Description:
  218. Starts SAP threads
  219. Arguments:
  220. None
  221. Return Value:
  222. NO_ERROR - threads started OK
  223. other (windows error code) - start failed
  224. *******************************************************************
  225. --*/
  226. DWORD
  227. StartSAP (
  228. VOID
  229. ) {
  230. DWORD status;
  231. status = StartLPC ();
  232. if (status==NO_ERROR) {
  233. status = StartIO ();
  234. if (status==NO_ERROR) {
  235. DWORD threadID;
  236. MainThreadHdl = CreateThread (NULL,
  237. 0,
  238. &MainThread,
  239. NULL,
  240. 0,
  241. &threadID);
  242. if (MainThreadHdl!=NULL) {
  243. OperationalState = OPER_STATE_UP;
  244. return NO_ERROR;
  245. }
  246. else {
  247. status = GetLastError ();
  248. Trace (DEBUG_FAILURES, "File: %s, line %ld."
  249. " Failed to launch IO thread (gle:%ld).",
  250. __FILE__, __LINE__, status);
  251. }
  252. StopIO ();
  253. }
  254. ShutdownLPC ();
  255. }
  256. OperationalState = OPER_STATE_DOWN;
  257. return status;
  258. }
  259. /*++
  260. *******************************************************************
  261. S t o p S A P
  262. Routine Description:
  263. Signals SAP threads to stop
  264. Arguments:
  265. No used
  266. Return Value:
  267. None
  268. *******************************************************************
  269. --*/
  270. VOID
  271. StopSAP (
  272. void
  273. ) {
  274. BOOL res;
  275. OperationalState = OPER_STATE_STOPPING;
  276. StopTime = GetTickCount ()+ShutdownTimeout*1000;
  277. res = SetEvent (WaitObjects[STOP_EVENT_IDX]);
  278. ASSERTERRMSG ("Could not set stop event in StopSAP ", res);
  279. }
  280. /*++
  281. *******************************************************************
  282. R e s u l t R e t r e i v e d C B
  283. Routine Description:
  284. Async result manager call back routine that signals IO thread when
  285. stop message is retreived by router manager
  286. Arguments:
  287. No used
  288. Return Value:
  289. None
  290. *******************************************************************
  291. --*/
  292. VOID
  293. ResultRetreivedCB (
  294. PAR_PARAM_BLOCK rslt
  295. ) {
  296. BOOL res;
  297. UNREFERENCED_PARAMETER(rslt);
  298. res = SetEvent (WaitObjects[STOP_EVENT_IDX]);
  299. ASSERTERRMSG ("Could not set stop event in result retreived CB", res);
  300. }
  301. /*++
  302. *******************************************************************
  303. M a i n T h r e a d
  304. Routine Description:
  305. Thread in which context we'll perform async IO and maintain timer
  306. queues.
  307. It is also used to launch and control other threads of SAP agent
  308. Arguments:
  309. None
  310. Return Value:
  311. None
  312. *******************************************************************
  313. --*/
  314. DWORD WINAPI
  315. MainThread (
  316. LPVOID param
  317. ) {
  318. DWORD status;
  319. UINT i;
  320. DWORD nObjects;
  321. HANDLE enumHdl;
  322. HINSTANCE hModule;
  323. hModule = LoadLibrary (ModuleName);
  324. Restart:
  325. Routing = RouterIfActive;
  326. if (Routing) {
  327. nObjects = ROUTING_NUM_OF_OBJECTS;
  328. }
  329. else {
  330. nObjects = STANDALONE_NUM_OF_OBJECTS;
  331. }
  332. while ((status = WaitForMultipleObjectsEx (
  333. nObjects,
  334. WaitObjects,
  335. FALSE, // Wait any
  336. INFINITE,
  337. TRUE))!=WAIT_OBJECT_0+STOP_EVENT_IDX) {
  338. switch (status) {
  339. case WAIT_OBJECT_0+RECV_COMPLETED_IDX:
  340. InitReqItem ();
  341. break;
  342. case WAIT_OBJECT_0+TIMER_WAKEUP_IDX:
  343. ProcessTimerQueue ();
  344. break;
  345. case WAIT_OBJECT_0+SERVER_TABLE_TIMER_IDX:
  346. ProcessExpirationQueue ();
  347. break;
  348. case WAIT_OBJECT_0+SERVER_TABLE_UPDATE_IDX:
  349. UpdateSortedList ();
  350. break;
  351. case WAIT_OBJECT_0+ADAPTER_CHG_IDX:
  352. if (!RouterIfActive)
  353. ProcessAdapterEvents ();
  354. break;
  355. case WAIT_IO_COMPLETION:
  356. break;
  357. default:
  358. ASSERTMSG ("Unexpected return code from WaitFromObjects"
  359. " in IO thread ", FALSE);
  360. break;
  361. }
  362. }
  363. enumHdl = CreateListEnumerator (SDB_HASH_TABLE_LINK,
  364. 0xFFFF,
  365. NULL,
  366. INVALID_INTERFACE_INDEX,
  367. 0xFFFFFFFF,
  368. SDB_DISABLED_NODE_FLAG);
  369. if (ServiceIfActive || RouterIfActive) {
  370. if (enumHdl!=NULL)
  371. EnumerateServers (enumHdl, DeleteNonLocalServersCB, enumHdl);
  372. }
  373. else {
  374. ShutdownLPC ();
  375. if (enumHdl!=NULL)
  376. EnumerateServers (enumHdl, DeleteAllServersCB, enumHdl);
  377. }
  378. if (enumHdl)
  379. {
  380. DeleteListEnumerator (enumHdl);
  381. }
  382. if (!RouterIfActive) {
  383. ShutdownInterfaces (WaitObjects[STOP_EVENT_IDX]);
  384. ExpireTimerQueue ();
  385. while ((status = WaitForMultipleObjectsEx (
  386. ROUTING_NUM_OF_OBJECTS,
  387. WaitObjects,
  388. FALSE, // Wait any
  389. INFINITE,
  390. TRUE))!=WAIT_OBJECT_0+STOP_EVENT_IDX) {
  391. switch (status) {
  392. case WAIT_OBJECT_0+RECV_COMPLETED_IDX:
  393. // No more recv requests
  394. break;
  395. case WAIT_OBJECT_0+TIMER_WAKEUP_IDX:
  396. ProcessTimerQueue ();
  397. break;
  398. case WAIT_OBJECT_0+SERVER_TABLE_TIMER_IDX:
  399. ProcessExpirationQueue ();
  400. break;
  401. case WAIT_OBJECT_0+SERVER_TABLE_UPDATE_IDX:
  402. UpdateSortedList ();
  403. break;
  404. case WAIT_IO_COMPLETION:
  405. break;
  406. default:
  407. ASSERTMSG ("Unexpected return code from WaitForObjects"
  408. " in IO thread", FALSE);
  409. }
  410. }
  411. if (!ServiceIfActive) {
  412. StopIO ();
  413. StopInterfaces ();
  414. ExpireTimerQueue ();
  415. ShutdownWorkers (WaitObjects[STOP_EVENT_IDX]);
  416. while ((status=WaitForSingleObjectEx (
  417. WaitObjects[STOP_EVENT_IDX],
  418. INFINITE,
  419. TRUE))!=WAIT_OBJECT_0) {
  420. switch (status) {
  421. case WAIT_IO_COMPLETION:
  422. break;
  423. default:
  424. ASSERTMSG (
  425. "Unexpected status when waiting for worker shutdown ",
  426. FALSE);
  427. break;
  428. }
  429. }
  430. }
  431. }
  432. if (Routing) {
  433. // Signal completion of stop operation to
  434. // router manager
  435. static AR_PARAM_BLOCK ar;
  436. ar.event = ROUTER_STOPPED;
  437. ar.freeRsltCB = ResultRetreivedCB;
  438. EnqueueResult (&ar);
  439. while ((status = WaitForSingleObjectEx (
  440. WaitObjects[STOP_EVENT_IDX],
  441. INFINITE,
  442. TRUE))!=WAIT_OBJECT_0) {
  443. switch (status) {
  444. case WAIT_IO_COMPLETION:
  445. break;
  446. default:
  447. ASSERTMSG (
  448. "Unexpected status when waiting for router callback ",
  449. FALSE);
  450. break;
  451. }
  452. }
  453. DeleteResultQueue ();
  454. if (ServiceIfActive) {
  455. status = CreateAdapterPort (&WaitObjects[ADAPTER_CHG_IDX]);
  456. if (status==NO_ERROR) {
  457. EnterCriticalSection (&OperationalStateLock);
  458. OperationalState = OPER_STATE_UP;
  459. LeaveCriticalSection (&OperationalStateLock);
  460. goto Restart;
  461. }
  462. else
  463. ServiceIfActive = FALSE;
  464. }
  465. EnterCriticalSection (&OperationalStateLock);
  466. CloseHandle (MainThreadHdl);
  467. MainThreadHdl = NULL;
  468. LeaveCriticalSection (&OperationalStateLock);
  469. }
  470. else {
  471. DeleteAdapterPort ();
  472. WaitObjects [ADAPTER_CHG_IDX] = NULL;
  473. if (RouterIfActive) {
  474. EnterCriticalSection (&OperationalStateLock);
  475. OperationalState = OPER_STATE_UP;
  476. LeaveCriticalSection (&OperationalStateLock);
  477. goto Restart;
  478. }
  479. }
  480. // Make sure all threads get a chance to complete
  481. Sleep (1000);
  482. DeleteAllComponents ();
  483. FreeLibraryAndExitThread (hModule, 0);
  484. return 0;
  485. }
  486. #define MYTEXTW1(str) L##str
  487. #define MYTEXTW2(str) MYTEXTW1(str)
  488. #define REGISTRY_PARAM_ENTRY(name,val) { \
  489. NULL, \
  490. RTL_QUERY_REGISTRY_DIRECT, \
  491. MYTEXTW2(name##_STR), \
  492. &val, \
  493. REG_DWORD, \
  494. &val, \
  495. sizeof (DWORD) \
  496. }
  497. #define REGISTRY_CHECK(name,val) { \
  498. if (val<name##_MIN) { \
  499. Trace (DEBUG_FAILURES, name##_STR " is to small %ld!", val); \
  500. val = name##_MIN; \
  501. } \
  502. else if (val>name##_MAX) { \
  503. Trace (DEBUG_FAILURES, name##_STR " is to big %ld!", val); \
  504. val = name##_MAX; \
  505. } \
  506. if (val!=name##_DEF) \
  507. Trace (DEBUG_FAILURES, name##_STR" is set to %ld.", val); \
  508. }
  509. #define REGISTRY_CHECK_DEF(name,val) { \
  510. if (val<name##_MIN) { \
  511. Trace (DEBUG_FAILURES, name##_STR " is to small %ld!", val); \
  512. val = name##_DEF; \
  513. } \
  514. else if (val>name##_MAX) { \
  515. Trace (DEBUG_FAILURES, name##_STR " is to big %ld!", val); \
  516. val = name##_DEF; \
  517. } \
  518. if (val!=name##_DEF) \
  519. Trace (DEBUG_FAILURES, name##_STR " is set to %ld.", val); \
  520. }
  521. VOID
  522. ReadRegistry (
  523. VOID
  524. ) {
  525. DWORD rc;
  526. HKEY hKey;
  527. static RTL_QUERY_REGISTRY_TABLE ParamTable[] = {
  528. { NULL,
  529. RTL_QUERY_REGISTRY_SUBKEY,
  530. L"Parameters" },
  531. REGISTRY_PARAM_ENTRY (SAP_UPDATE_INTERVAL, UpdateInterval),
  532. REGISTRY_PARAM_ENTRY (SAP_AGING_TIMEOUT, ServerAgingTimeout),
  533. REGISTRY_PARAM_ENTRY (SAP_WAN_UPDATE_MODE, WanUpdateMode),
  534. REGISTRY_PARAM_ENTRY (SAP_WAN_UPDATE_INTERVAL,WanUpdateInterval),
  535. REGISTRY_PARAM_ENTRY (SAP_MAX_UNPROCESSED_REQUESTS,
  536. MaxUnprocessedRequests),
  537. REGISTRY_PARAM_ENTRY (SAP_RESPOND_FOR_INTERNAL,
  538. RespondForInternalServers),
  539. REGISTRY_PARAM_ENTRY (SAP_DELAY_RESPONSE_TO_GENERAL,
  540. DelayResponseToGeneral),
  541. REGISTRY_PARAM_ENTRY (SAP_DELAY_CHANGE_BROADCAST,
  542. DelayChangeBroadcast),
  543. REGISTRY_PARAM_ENTRY (SAP_SDB_MAX_HEAP_SIZE,SDBMaxHeapSize),
  544. REGISTRY_PARAM_ENTRY (SAP_SDB_SORT_LATENCY, SDBSortLatency),
  545. REGISTRY_PARAM_ENTRY (SAP_SDB_MAX_UNSORTED, SDBMaxUnsortedServers),
  546. REGISTRY_PARAM_ENTRY (SAP_TRIGGERED_UPDATE_CHECK_INTERVAL,
  547. TriggeredUpdateCheckInterval),
  548. REGISTRY_PARAM_ENTRY (SAP_MAX_TRIGGERED_UPDATE_REQUESTS,
  549. MaxTriggeredUpdateRequests),
  550. REGISTRY_PARAM_ENTRY (SAP_SHUTDOWN_TIMEOUT, ShutdownTimeout),
  551. REGISTRY_PARAM_ENTRY (SAP_REQUESTS_PER_INTF,NewRequestsPerInterface),
  552. REGISTRY_PARAM_ENTRY (SAP_MIN_REQUESTS, MinPendingRequests),
  553. {
  554. NULL
  555. }
  556. };
  557. rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  558. TEXT (SAP_ROUTER_REGISTRY_KEY_STR),
  559. 0,
  560. KEY_READ,
  561. &hKey
  562. );
  563. if ((rc!=NO_ERROR) && !Routing) {
  564. rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  565. TEXT (SAP_SERVICE_REGISTRY_KEY_STR),
  566. 0,
  567. KEY_READ,
  568. &hKey
  569. );
  570. }
  571. if (rc==NO_ERROR) {
  572. NTSTATUS status;
  573. status = RtlQueryRegistryValues(
  574. RTL_REGISTRY_HANDLE,
  575. (PWSTR)hKey,
  576. ParamTable,
  577. NULL,
  578. NULL);
  579. if (NT_SUCCESS (status)) {
  580. REGISTRY_CHECK (SAP_UPDATE_INTERVAL, UpdateInterval);
  581. REGISTRY_CHECK (SAP_AGING_TIMEOUT, ServerAgingTimeout);
  582. REGISTRY_CHECK_DEF (SAP_WAN_UPDATE_MODE, (int)WanUpdateMode);
  583. REGISTRY_CHECK (SAP_WAN_UPDATE_INTERVAL,WanUpdateInterval);
  584. REGISTRY_CHECK (SAP_MAX_UNPROCESSED_REQUESTS,
  585. MaxUnprocessedRequests);
  586. REGISTRY_CHECK_DEF (SAP_RESPOND_FOR_INTERNAL,
  587. (int) RespondForInternalServers);
  588. REGISTRY_CHECK (SAP_DELAY_RESPONSE_TO_GENERAL,
  589. (int) DelayResponseToGeneral);
  590. REGISTRY_CHECK (SAP_DELAY_CHANGE_BROADCAST,
  591. (int) DelayChangeBroadcast);
  592. REGISTRY_CHECK (SAP_SDB_MAX_HEAP_SIZE, SDBMaxHeapSize);
  593. REGISTRY_CHECK (SAP_SDB_SORT_LATENCY, SDBSortLatency);
  594. REGISTRY_CHECK (SAP_SDB_MAX_UNSORTED, SDBMaxUnsortedServers);
  595. REGISTRY_CHECK (SAP_TRIGGERED_UPDATE_CHECK_INTERVAL,
  596. TriggeredUpdateCheckInterval);
  597. REGISTRY_CHECK (SAP_MAX_TRIGGERED_UPDATE_REQUESTS,
  598. MaxTriggeredUpdateRequests);
  599. REGISTRY_CHECK (SAP_SHUTDOWN_TIMEOUT, ShutdownTimeout);
  600. REGISTRY_CHECK (SAP_REQUESTS_PER_INTF, NewRequestsPerInterface);
  601. REGISTRY_CHECK (SAP_MIN_REQUESTS, MinPendingRequests);
  602. }
  603. RegCloseKey (hKey);
  604. }
  605. }