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.

891 lines
25 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. worker.c
  5. Abstract:
  6. Workter threads used by the web dav mini-redir client service.
  7. Author:
  8. Andy Herron (andyhe) 15-Apr-1999
  9. Rohan Kumar [RohanK] 05-May-1999
  10. Environment:
  11. User Mode - Win32
  12. Revision History:
  13. --*/
  14. #include "pch.h"
  15. #pragma hdrstop
  16. #include <ntumrefl.h>
  17. #include <usrmddav.h>
  18. #include "global.h"
  19. #include "nodefac.h"
  20. #define DAV_WORKITEM_ALLOC_FAIL_COUNT 10
  21. #define DAV_WORKITEM_ALLOC_FAIL_WAIT 250
  22. #define DAV_WORKITEM_FAIL_REQUEST 10
  23. #define DAV_WORKITEM_FAIL_REQUEST_WAIT 100
  24. LONG DavOutstandingWorkerRequests;
  25. typedef struct _UMFS_WORKER_THREAD {
  26. struct _UMFS_THREAD_CONSTELLATION *Constellation;
  27. HANDLE ThisThreadHandle;
  28. ULONG ThisThreadId;
  29. PDAV_USERMODE_WORKITEM pCurrentWorkItem;
  30. union {
  31. PVOID Context1;
  32. ULONG Context1u;
  33. };
  34. union {
  35. PVOID Context2;
  36. ULONG Context2u;
  37. };
  38. } UMFS_WORKER_THREAD, *PUMFS_WORKER_THREAD;
  39. typedef struct _UMFS_THREAD_CONSTELLATION {
  40. HANDLE DeviceObjectHandle;
  41. ULONG MaximumNumberOfWorkers;
  42. ULONG InitialNumberOfWorkers;
  43. BOOLEAN Terminating;
  44. UMFS_WORKER_THREAD WorkerThreads[1];
  45. } UMFS_THREAD_CONSTELLATION, *PUMFS_THREAD_CONSTELLATION;
  46. PUMFS_THREAD_CONSTELLATION DavThreadConstellation = NULL;
  47. //
  48. // Mentioned below are the prototypes of functions that are used only within
  49. // this module (file). These functions should not be exposed outside.
  50. //
  51. DWORD
  52. WINAPI
  53. DavRestartContext(
  54. LPVOID Context
  55. );
  56. DWORD
  57. DavPostWorkItem(
  58. LPTHREAD_START_ROUTINE Function,
  59. PDAV_USERMODE_WORKITEM DavContext
  60. );
  61. DWORD
  62. DavWorkerThread (
  63. PUMFS_WORKER_THREAD Worker
  64. );
  65. //
  66. // Implementation of functions begins here.
  67. //
  68. DWORD
  69. DavInitWorkerThreads(
  70. IN ULONG InitialThreadCount,
  71. IN ULONG MaxThreadCount
  72. )
  73. /*++
  74. Routine Description:
  75. This routines creates the threads to be sent down to the kernel.
  76. Arguments:
  77. InitialThreadCount - Initial number of threads sent down to get requests.
  78. MaxThreadCount - Max number of threads to be sent down to get requests.
  79. Return Value:
  80. The return status for the operation
  81. --*/
  82. {
  83. DWORD WStatus;
  84. ULONG ConstellationSize;
  85. ULONG i;
  86. DavOutstandingWorkerRequests = 0;
  87. //
  88. // We need to allocate MaxThread number of UMFS_WORKER_THREAD strucutres +
  89. // the UMFS_THREAD_CONSTELLATION. Since the UMFS_THREAD_CONSTELLATION
  90. // structure already contains one UMFS_WORKER_THREAD field, we allocate
  91. // memory for (MaxThreadCount - 1) UMFS_WORKER_THREAD strucutres +
  92. // UMFS_THREAD_CONSTELLATION.
  93. //
  94. ConstellationSize = sizeof(UMFS_THREAD_CONSTELLATION);
  95. ConstellationSize += ( (MaxThreadCount - 1) * sizeof(UMFS_WORKER_THREAD) );
  96. //
  97. // We need to make the ConstellationSize a multiple of 8. This is because
  98. // DavAllocateMemory calls DebugAlloc which does some stuff which requires
  99. // this. The equation below does this.
  100. //
  101. ConstellationSize = ( ( ( ConstellationSize + 7 ) / 8 ) * 8 );
  102. DavThreadConstellation = (PUMFS_THREAD_CONSTELLATION)
  103. DavAllocateMemory(ConstellationSize);
  104. if (DavThreadConstellation == NULL) {
  105. WStatus = GetLastError();
  106. DavPrint((DEBUG_ERRORS,
  107. "DavInitWorkerThreads/DavAllocateMemory. Error Val = %d.\n",
  108. WStatus));
  109. return WStatus;
  110. }
  111. DavThreadConstellation->Terminating = FALSE;
  112. DavThreadConstellation->InitialNumberOfWorkers = InitialThreadCount;
  113. DavThreadConstellation->MaximumNumberOfWorkers = MaxThreadCount;
  114. DavThreadConstellation->DeviceObjectHandle = DavRedirDeviceHandle;
  115. DavPrint((DEBUG_MISC,
  116. "DavInitWorkerThreads: Dav Thread Constellation allocated at "
  117. "0x%x\n", DavThreadConstellation));
  118. //
  119. // Just spin up initial threads and ignore the max.
  120. //
  121. for (i = 0; i < InitialThreadCount; i++) {
  122. PUMFS_WORKER_THREAD Worker = &(DavThreadConstellation->WorkerThreads[i]);
  123. Worker->Constellation = DavThreadConstellation;
  124. Worker->ThisThreadHandle = CreateThread(
  125. NULL,
  126. 0,
  127. (LPTHREAD_START_ROUTINE)DavWorkerThread,
  128. (LPVOID)Worker,
  129. 0,
  130. &Worker->ThisThreadId);
  131. if (Worker->ThisThreadHandle == NULL) {
  132. WStatus = GetLastError();
  133. DavPrint((DEBUG_ERRORS,
  134. "DavInitWorkerThreads/CreateThread: Return Val is NULL. "
  135. "Error Val = %08lx.\n", WStatus));
  136. } else {
  137. DavPrint((DEBUG_MISC, "DavInitWorkerThreads: Dav Thread %u has "
  138. "ThreadId 0x%x and Handle 0x%x\n",
  139. i, Worker->ThisThreadId, Worker->ThisThreadHandle));
  140. }
  141. }
  142. return STATUS_SUCCESS;
  143. }
  144. DWORD
  145. DavTerminateWorkerThreads(
  146. VOID
  147. )
  148. /*++
  149. Routine Description:
  150. This routines terminates the threads sent down to the kernel.
  151. Arguments:
  152. none.
  153. Return Value:
  154. The return status for the operation
  155. --*/
  156. {
  157. DWORD WStatus = ERROR_SUCCESS;
  158. ULONG i = 0;
  159. OVERLAPPED OverLapped;
  160. if (DavThreadConstellation != NULL) {
  161. DavThreadConstellation->Terminating = TRUE;
  162. //
  163. // First we complete all pending IRPs waiting down in kernel so that we
  164. // can kill these threads.
  165. //
  166. WStatus = UMReflectorReleaseThreads(DavReflectorHandle);
  167. if (WStatus != ERROR_SUCCESS) {
  168. DavPrint((DEBUG_ERRORS,
  169. "DavTerminateWorkerThreads/UMReflectorReleaseThreads: "
  170. "Error value returned = %u.\n", WStatus));
  171. }
  172. }
  173. //
  174. // We ensure all worker threads have completed before we close the ioctl
  175. // threads.
  176. //
  177. while (DavOutstandingWorkerRequests) {
  178. //
  179. // Wait for a 250 milliseconds to check again for all threads to have
  180. // completed.
  181. //
  182. Sleep(250);
  183. }
  184. if (DavThreadConstellation != NULL) {
  185. for ( i = 0; i < DavThreadConstellation->MaximumNumberOfWorkers; i++) {
  186. HANDLE ThreadHandle =
  187. DavThreadConstellation->WorkerThreads[i].ThisThreadHandle;
  188. if (ThreadHandle != NULL) {
  189. DavPrint((DEBUG_MISC,
  190. "DavTerminateWorkerThread: Waiting for ThreadId 0x%x"
  191. ", ThreadHandle 0x%x.\n",
  192. DavThreadConstellation->WorkerThreads[i].ThisThreadId,
  193. ThreadHandle));
  194. WaitForSingleObject(ThreadHandle, INFINITE);
  195. NtClose(ThreadHandle);
  196. }
  197. }
  198. //
  199. // Now that we're done with the constellation, we free it.
  200. //
  201. DavFreeMemory(DavThreadConstellation);
  202. DavThreadConstellation = NULL;
  203. }
  204. return STATUS_SUCCESS;
  205. }
  206. DWORD
  207. WINAPI
  208. DavRestartContext(
  209. LPVOID Context
  210. )
  211. /*++
  212. Routine Description:
  213. This function gets called when a worker thread initiates work on one
  214. of our contexts. We'll call off to the restart routine and then
  215. decrement the count of active work contexts. The argument passed to the
  216. restart routine is the context itself.
  217. Arguments:
  218. Context - The context which contains the function to be called.
  219. Return Value:
  220. ERROR_SUCCESS or the appropriate error value.
  221. --*/
  222. {
  223. DWORD err;
  224. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  225. PDAV_USERMODE_WORKITEM davContext = NULL;
  226. LPTHREAD_START_ROUTINE routine = NULL;
  227. davContext = (PDAV_USERMODE_WORKITEM) Context;
  228. routine = (LPTHREAD_START_ROUTINE) davContext->RestartRoutine;
  229. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)davContext;
  230. //
  231. // We store the ThreadId in the DAV_USERMODE_WORKITEM structure for
  232. // debugging purposes.
  233. //
  234. davContext->ThisThreadId = GetCurrentThreadId();
  235. DavPrint((DEBUG_MISC,
  236. "DavRestartContext: DavWorkItem = %08lx, ThisThreadId = %x\n",
  237. davContext, davContext->ThisThreadId));
  238. //
  239. // Invoke the function.
  240. //
  241. err = routine( (LPVOID)davContext );
  242. if (err != ERROR_SUCCESS && err != ERROR_IO_PENDING) {
  243. DavPrint((DEBUG_MISC,
  244. "DavRestartContext: Routine at address %08lx returned error of"
  245. " %08lx for context %08lx.\n", routine, err, davContext));
  246. }
  247. //
  248. // If we are using WinInet synchronously, then we need to finally complete
  249. // the request.
  250. //
  251. #ifndef DAV_USE_WININET_ASYNCHRONOUSLY
  252. //
  253. // This thread now needs to send the response back to the kernel. It
  254. // does not wait in the kernel (to get another request) after submitting
  255. // the response.
  256. //
  257. UMReflectorCompleteRequest(DavReflectorHandle, UserWorkItem);
  258. #endif
  259. //
  260. // Decrement the number of requests posted.
  261. //
  262. InterlockedDecrement( &(DavOutstandingWorkerRequests) );
  263. return err;
  264. }
  265. VOID
  266. DavCleanupWorkItem(
  267. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem
  268. )
  269. /*++
  270. Routine Description:
  271. This function gets called when a kernelmode requests gets cancelled and we
  272. need to do some cleanup to free up the resources allocated for the response
  273. of this request. For example, in QueryDirectory, we allocate a list of
  274. DavFileAttributes for every file in the directory. Since the request has
  275. been cancelled in the kernel, we don't need this list anymore.
  276. Arguments:
  277. UserWorkItem - The WorkItem that needs to be cleaned.
  278. Return Value:
  279. None.
  280. --*/
  281. {
  282. PDAV_USERMODE_WORKITEM davContext = NULL;
  283. PDAV_USERMODE_QUERYDIR_RESPONSE QueryDirResponse = NULL;
  284. PDAV_USERMODE_CREATE_RESPONSE CreateResponse = NULL;
  285. davContext = (PDAV_USERMODE_WORKITEM)UserWorkItem;
  286. switch (davContext->WorkItemType) {
  287. case UserModeQueryDirectory: {
  288. QueryDirResponse = &(davContext->QueryDirResponse);
  289. DavFinalizeFileAttributesList(QueryDirResponse->DavFileAttributes, TRUE);
  290. QueryDirResponse->DavFileAttributes = NULL;
  291. }
  292. break;
  293. case UserModeCreate: {
  294. CreateResponse = &(davContext->CreateResponse);
  295. NtClose(CreateResponse->Handle);
  296. CreateResponse->Handle = NULL;
  297. }
  298. break;
  299. }
  300. return;
  301. }
  302. DWORD
  303. DavPostWorkItem(
  304. LPTHREAD_START_ROUTINE Function,
  305. PDAV_USERMODE_WORKITEM DavContext
  306. )
  307. /*++
  308. Routine Description:
  309. This function should be called to post a dav work context to a worker
  310. thread. We track the number of outstanding requests we have.
  311. Arguments:
  312. Function - The Functon to be called by the worker thread.
  313. DavContext - The context to be passed to the function.
  314. Return Value:
  315. ERROR_SUCCESS or the appropriate error value.
  316. --*/
  317. {
  318. DWORD err = ERROR_SUCCESS;
  319. BOOL qResult;
  320. DavContext->RestartRoutine = (LPVOID)Function;
  321. //
  322. // Increment the number of requests posted.
  323. //
  324. InterlockedIncrement( &(DavOutstandingWorkerRequests) );
  325. //
  326. // Queue the workitem context.
  327. //
  328. qResult = QueueUserWorkItem(DavRestartContext, (LPVOID)DavContext, 0);
  329. if (!qResult) {
  330. //
  331. // Decrement the number of requests posted.
  332. //
  333. InterlockedDecrement( &(DavOutstandingWorkerRequests) );
  334. err = GetLastError();
  335. DavPrint((DEBUG_ERRORS,
  336. "DavPostWorkItem/QueueUserWorkItem: WStatus = %08lx.\n", err));
  337. }
  338. return err;
  339. }
  340. DWORD
  341. DavWorkerThread (
  342. PUMFS_WORKER_THREAD Worker
  343. )
  344. /*++
  345. Routine Description:
  346. This is the routine that gets kicked off by the worker thread. It issues
  347. synchronous IOCTL's to the user mode reflctor. Whenever a request comes
  348. down to the reflector, it uses these IOCTL's to pass the request back to the
  349. user mode. On return, the output buffers contain the request that came down
  350. to the reflctor. The routine looks at the request type and appropriately
  351. handles it. The results are sent back to the reflctor in a similar fashion.
  352. Arguments:
  353. Worker - The worker thread's data structure.
  354. Return Value:
  355. None.
  356. --*/
  357. {
  358. DWORD err = ERROR_SUCCESS;
  359. PDAV_USERMODE_WORKITEM WorkItemToUse = NULL;
  360. PUMRX_USERMODE_WORKITEM_HEADER WorkItemToSendBack = NULL;
  361. PUMFS_THREAD_CONSTELLATION Constellation = Worker->Constellation;
  362. ULONG NumberOfBytesTransferred;
  363. DWORD CompletionKey;
  364. ULONG failedMallocCount = 0;
  365. ULONG failedGetRequest = 0;
  366. PUMRX_USERMODE_WORKER_INSTANCE davWorkerHandle = NULL;
  367. BOOL didCreateImpersonationToken = FALSE, revertAlreadyDone = FALSE;
  368. Worker->Context1u = (ULONG)(Worker - &Constellation->WorkerThreads[0]);
  369. DavPrint((DEBUG_MISC,
  370. "DavWorkerThread: DavClient Thread (handle = %08lx and id = %08lx)"
  371. "starting...\n", Worker->ThisThreadHandle, Worker->ThisThreadId));
  372. err = UMReflectorOpenWorker(DavReflectorHandle, &davWorkerHandle);
  373. if (err != ERROR_SUCCESS || davWorkerHandle == NULL) {
  374. if (err == ERROR_SUCCESS) {
  375. err = ERROR_INTERNAL_ERROR;
  376. }
  377. DavPrint((DEBUG_ERRORS,
  378. "DavWorkerThread: DavClient thread %08lx error %u on OpenWorker.\n",
  379. Worker->ThisThreadId, err));
  380. goto ExitWorker;
  381. }
  382. //
  383. // Continue servicing requests till the thread constellation is active.
  384. //
  385. while (Constellation->Terminating == FALSE) {
  386. //
  387. // If there is no WorkItem associated with this thread, then get one
  388. // for it.
  389. //
  390. if (WorkItemToUse == NULL) {
  391. WorkItemToUse = (PDAV_USERMODE_WORKITEM)
  392. UMReflectorAllocateWorkItem(
  393. davWorkerHandle,
  394. (sizeof(DAV_USERMODE_WORKITEM) -
  395. sizeof(UMRX_USERMODE_WORKITEM_HEADER)) +
  396. sizeof(ULONG));
  397. if (WorkItemToUse == NULL) {
  398. DavPrint((DEBUG_ERRORS,
  399. "DavWorkerThread: DavClient Thread %08lx couldn't "
  400. "allocate workitem. Retry %u\n", Worker->ThisThreadId,
  401. DAV_WORKITEM_ALLOC_FAIL_COUNT - failedMallocCount));
  402. failedMallocCount++;
  403. if (failedMallocCount >= DAV_WORKITEM_ALLOC_FAIL_COUNT) {
  404. err = GetLastError();
  405. goto ExitWorker;
  406. }
  407. Sleep(DAV_WORKITEM_ALLOC_FAIL_WAIT);
  408. continue;
  409. }
  410. failedMallocCount = 0;
  411. }
  412. err = UMReflectorGetRequest(davWorkerHandle,
  413. WorkItemToSendBack,
  414. (PUMRX_USERMODE_WORKITEM_HEADER)WorkItemToUse,
  415. revertAlreadyDone);
  416. if (WorkItemToSendBack) {
  417. UMReflectorCompleteWorkItem(davWorkerHandle, WorkItemToSendBack);
  418. WorkItemToSendBack = NULL;
  419. }
  420. if (err != ERROR_SUCCESS) {
  421. DavPrint((DEBUG_ERRORS,
  422. "DavWorkerThread/UMReflectorGetRequest: Thread: %08lx, "
  423. "Error: %08lx,. Retry: %d\n", Worker->ThisThreadId, err,
  424. DAV_WORKITEM_FAIL_REQUEST - failedGetRequest));
  425. failedGetRequest++;
  426. if ((failedGetRequest >= DAV_WORKITEM_FAIL_REQUEST) ||
  427. (Constellation->Terminating == TRUE)) {
  428. goto ExitWorker;
  429. }
  430. DavPrint((DEBUG_MISC,
  431. "DavWorkerThread: DavClient thread %08lx waiting for small time\n",
  432. Worker->ThisThreadId ));
  433. Sleep(DAV_WORKITEM_FAIL_REQUEST_WAIT);
  434. continue;
  435. }
  436. failedGetRequest = 0;
  437. //
  438. // If we are using WinInet synchronously, then we need to set the
  439. // impersonation token before we post this request to the Win32 thread
  440. // pool. We dont do this in the case of finalizesrvcall or finalizefobx
  441. // becuase these requests don't go over the network.
  442. //
  443. switch (WorkItemToUse->WorkItemType) {
  444. case UserModeCreate:
  445. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  446. err = DavFsCreate(WorkItemToUse);
  447. #else
  448. err = DavFsSetTheDavCallBackContext(WorkItemToUse);
  449. if (err == ERROR_SUCCESS) {
  450. //
  451. // We need to Revert before calling the DavPostWorkItem function
  452. // below to post this workitem to a Win32 thread. Otherwise the
  453. // worker thread will not able to to impersonate the user later.
  454. //
  455. RevertToSelf();
  456. //
  457. // Set this to TRUE since we don't need to revert back in the
  458. // kernel any more.
  459. //
  460. revertAlreadyDone = TRUE;
  461. didCreateImpersonationToken = TRUE;
  462. err = DavPostWorkItem(DavFsCreate, WorkItemToUse);
  463. }
  464. #endif
  465. break;
  466. case UserModeCreateSrvCall:
  467. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  468. err = DavFsCreateSrvCall(WorkItemToUse);
  469. #else
  470. err = DavFsSetTheDavCallBackContext(WorkItemToUse);
  471. if (err == ERROR_SUCCESS) {
  472. RevertToSelf();
  473. revertAlreadyDone = TRUE;
  474. didCreateImpersonationToken = TRUE;
  475. err = DavPostWorkItem(DavFsCreateSrvCall, WorkItemToUse);
  476. }
  477. #endif
  478. break;
  479. case UserModeCreateVNetRoot:
  480. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  481. err = DavFsCreateVNetRoot(WorkItemToUse);
  482. #else
  483. err = DavFsSetTheDavCallBackContext(WorkItemToUse);
  484. if (err == ERROR_SUCCESS) {
  485. RevertToSelf();
  486. revertAlreadyDone = TRUE;
  487. didCreateImpersonationToken = TRUE;
  488. err = DavPostWorkItem(DavFsCreateVNetRoot, WorkItemToUse);
  489. }
  490. #endif
  491. break;
  492. case UserModeFinalizeSrvCall:
  493. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  494. err = DavFsFinalizeSrvCall(WorkItemToUse);
  495. #else
  496. err = DavPostWorkItem(DavFsFinalizeSrvCall, WorkItemToUse);
  497. #endif
  498. break;
  499. case UserModeFinalizeVNetRoot:
  500. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  501. err = DavFsFinalizeVNetRoot(WorkItemToUse);
  502. #else
  503. err = DavPostWorkItem(DavFsFinalizeVNetRoot, WorkItemToUse);
  504. #endif
  505. break;
  506. case UserModeFinalizeFobx:
  507. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  508. err = DavFsFinalizeFobx(WorkItemToUse);
  509. #else
  510. err = DavPostWorkItem(DavFsFinalizeFobx, WorkItemToUse);
  511. #endif
  512. break;
  513. //
  514. // Check to see if we have already created the DavFileAttributes
  515. // list. If we have, we are already done and just need to return.
  516. // If we have not, then we post the request.
  517. //
  518. case UserModeQueryDirectory:
  519. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  520. err = DavFsQueryDirectory(WorkItemToUse);
  521. #else
  522. err = DavFsSetTheDavCallBackContext(WorkItemToUse);
  523. if (err == ERROR_SUCCESS) {
  524. RevertToSelf();
  525. revertAlreadyDone = TRUE;
  526. didCreateImpersonationToken = TRUE;
  527. err = DavPostWorkItem(DavFsQueryDirectory, WorkItemToUse);
  528. }
  529. #endif
  530. break;
  531. case UserModeQueryVolumeInformation:
  532. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  533. err = DavFsQueryVolumeInformation(WorkItemToUse);
  534. #else
  535. err = DavFsSetTheDavCallBackContext(WorkItemToUse);
  536. if (err == ERROR_SUCCESS) {
  537. RevertToSelf();
  538. revertAlreadyDone = TRUE;
  539. didCreateImpersonationToken = TRUE;
  540. err = DavPostWorkItem(DavFsQueryVolumeInformation, WorkItemToUse);
  541. }
  542. #endif
  543. break;
  544. case UserModeReName:
  545. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  546. err = DavFsReName(WorkItemToUse);
  547. #else
  548. err = DavFsSetTheDavCallBackContext(WorkItemToUse);
  549. if (err == ERROR_SUCCESS) {
  550. RevertToSelf();
  551. revertAlreadyDone = TRUE;
  552. didCreateImpersonationToken = TRUE;
  553. err = DavPostWorkItem(DavFsReName, WorkItemToUse);
  554. }
  555. #endif
  556. break;
  557. case UserModeClose:
  558. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  559. err = DavFsClose(WorkItemToUse);
  560. #else
  561. err = DavFsSetTheDavCallBackContext(WorkItemToUse);
  562. if (err == ERROR_SUCCESS) {
  563. RevertToSelf();
  564. revertAlreadyDone = TRUE;
  565. didCreateImpersonationToken = TRUE;
  566. err = DavPostWorkItem(DavFsClose, WorkItemToUse);
  567. }
  568. #endif
  569. break;
  570. case UserModeSetFileInformation:
  571. err = DavFsSetTheDavCallBackContext(WorkItemToUse);
  572. if (err == ERROR_SUCCESS) {
  573. RevertToSelf();
  574. revertAlreadyDone = TRUE;
  575. didCreateImpersonationToken = TRUE;
  576. err = DavPostWorkItem(DavFsSetFileInformation, WorkItemToUse);
  577. }
  578. break;
  579. case UserModeLockRefresh:
  580. err = DavFsSetTheDavCallBackContext(WorkItemToUse);
  581. if (err == ERROR_SUCCESS) {
  582. RevertToSelf();
  583. revertAlreadyDone = TRUE;
  584. didCreateImpersonationToken = TRUE;
  585. err = DavPostWorkItem(DavFsLockRefresh, WorkItemToUse);
  586. }
  587. break;
  588. default:
  589. DavPrint((DEBUG_ERRORS,
  590. "DavWorkerThread: Invalid WorkItemType = %d.\n",
  591. WorkItemToUse->WorkItemType));
  592. break;
  593. }
  594. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  595. //
  596. // If ERROR_IO_PENDING has been returned by the function that is
  597. // handling this request, it means that the request will be completed
  598. // in the context of some worker thread. So, this thread is done with
  599. // the workitem and should discard (not worry) about (completing) it.
  600. //
  601. if (err == ERROR_IO_PENDING) {
  602. WorkItemToUse = NULL;
  603. }
  604. #else
  605. //
  606. // If we are using WinInet synchronously, we would have posted the
  607. // request to the Win32 thread pool. If the request was successfully
  608. // queued, then the worker thread that picks it up will ultimately
  609. // complete it.
  610. //
  611. if (err == ERROR_SUCCESS) {
  612. WorkItemToUse = NULL;
  613. } else {
  614. DavPrint((DEBUG_ERRORS, "DavWorkerThread/DavPostWorkItem: err = %d\n", err));
  615. //
  616. // If we created the impersonation token, we need to close it now
  617. // since we falied to post the request.
  618. //
  619. if (didCreateImpersonationToken) {
  620. DavFsFinalizeTheDavCallBackContext(WorkItemToUse);
  621. }
  622. WorkItemToUse->Status = DavDosErrorToNtStatus(err);
  623. //
  624. // The error cannot map to STATUS_SUCCESS. If it does, we need to
  625. // break here and investigate.
  626. //
  627. if (WorkItemToUse->Status == STATUS_SUCCESS) {
  628. DbgBreakPoint();
  629. }
  630. }
  631. #endif
  632. //
  633. // If ERROR_IO_PENDING has been returned, there is nothing to send
  634. // back now. The above "if" takes care of this.
  635. //
  636. WorkItemToSendBack = (PUMRX_USERMODE_WORKITEM_HEADER)WorkItemToUse;
  637. //
  638. // This is set to NULL to pick up another workitem.
  639. //
  640. WorkItemToUse = NULL;
  641. }
  642. ExitWorker:
  643. if (WorkItemToSendBack) {
  644. ULONG SendStatus;
  645. SendStatus = UMReflectorSendResponse(davWorkerHandle, WorkItemToSendBack);
  646. if (SendStatus != ERROR_SUCCESS) {
  647. DavPrint((DEBUG_ERRORS,
  648. "DavWorkerThread/UMReflectorSendResponse: SendStatus = "
  649. "%08lx.\n", SendStatus));
  650. }
  651. UMReflectorCompleteWorkItem(davWorkerHandle, WorkItemToSendBack);
  652. }
  653. if (WorkItemToUse) {
  654. UMReflectorCompleteWorkItem(davWorkerHandle,
  655. (PUMRX_USERMODE_WORKITEM_HEADER)WorkItemToUse);
  656. }
  657. if (davWorkerHandle) {
  658. UMReflectorCloseWorker(davWorkerHandle);
  659. }
  660. DavPrint((DEBUG_MISC,
  661. "DavWorkerThread: DavClient thread %08lx exiting with error %u\n",
  662. Worker->ThisThreadId, err));
  663. //
  664. // This return, exits the thread.
  665. //
  666. return err;
  667. }
  668. // worker.c eof