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.

731 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1990 - 1999
  6. //
  7. // File: threads.hxx
  8. //
  9. //--------------------------------------------------------------------------
  10. /* --------------------------------------------------------------------
  11. Microsoft OS/2 LAN Manager
  12. Copyright(c) Microsoft Corp., 1990
  13. -------------------------------------------------------------------- */
  14. /* --------------------------------------------------------------------
  15. File: threads.hxx
  16. Description:
  17. This file provides a system independent threads package.
  18. History:
  19. mikemon 05/24/90 File created.
  20. mikemon 10/15/90 Added the PauseExecution entry point.
  21. Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
  22. -------------------------------------------------------------------- */
  23. #ifndef __THREADS__
  24. #define __THREADS__
  25. #include <interlck.hxx>
  26. class CALL;
  27. class LRPC_CCALL;
  28. class SCALL;
  29. typedef BOOL
  30. (*THREAD_PROC) (
  31. void * Parameter
  32. );
  33. typedef HANDLE THREAD_IDENTIFIER;
  34. class THREAD
  35. {
  36. friend void
  37. RpcpPurgeEEInfoFromThreadIfNecessary (
  38. IN THREAD *ThisThread
  39. );
  40. private:
  41. static const unsigned int CallDestroyedWithOutstandingLocks = 1;
  42. static const unsigned int CallCancelled = 2;
  43. static const unsigned int Yielded = 4;
  44. #ifdef RPC_OLD_IO_PROTECTION
  45. LONG ProtectCount;
  46. #endif
  47. public:
  48. BOOL fAsync;
  49. long CancelTimeout;
  50. private:
  51. HANDLE HandleToThread;
  52. public:
  53. EVENT ThreadEvent;
  54. void * Context;
  55. void * SecurityContext;
  56. BCACHE_STATE BufferCache[4];
  57. // write-on-multiple-threads section, buffered with unused (rarely used) variables
  58. RPC_STATUS ExtendedStatus;
  59. CellTag DebugCellTag;
  60. DebugThreadInfo *DebugCell;
  61. private:
  62. THREAD_PROC SavedProcedure;
  63. void * SavedParameter;
  64. CALL * ActiveCall;
  65. #ifdef RPC_OLD_IO_PROTECTION
  66. INTERLOCKED_INTEGER ReleaseCount;
  67. #endif
  68. ExtendedErrorInfo *ThreadEEInfo;
  69. void *NDRSlot;
  70. // a cached LRPC call - essnetially the same that a LRPC_CALL constructor
  71. // will give. This is never used in the non-server versions of the product
  72. LRPC_CCALL *CachedLrpcCall;
  73. CompositeFlags Flags;
  74. void *LastSuccessfullyDestroyedContext;
  75. // cached waiter blocks
  76. // a pointer to the last cached waiter we have. It must
  77. // never be equal to &CachedWaiter
  78. SWMRWaiter *CachedWaiterPtr;
  79. // a buffer where we can cookup a waiter using the thread event
  80. BOOL CachedWaiterAvailable;
  81. SWMRWaiter CachedWaiter;
  82. ExtendedErrorInfo *CachedEEInfoBlock;
  83. ULONG ParametersOfCachedEEInfo; // how many parameters does the
  84. // CachedEEInfoBlock has
  85. public:
  86. #ifdef CHECK_MUTEX_INVERSION
  87. void * ConnectionMutexHeld;
  88. #endif
  89. // Construct a new thread which will execute the procedure specified, taking
  90. // Param as the argument.
  91. THREAD (
  92. IN THREAD_PROC Procedure,
  93. IN void * Parameter,
  94. OUT RPC_STATUS * RpcStatus
  95. );
  96. THREAD (
  97. OUT RPC_STATUS * RpcStatus
  98. );
  99. ~THREAD (
  100. );
  101. void
  102. StartRoutine (
  103. ) {(*SavedProcedure)(SavedParameter);}
  104. void *
  105. ThreadHandle (
  106. );
  107. friend THREAD * ThreadSelf();
  108. friend void * RpcpGetThreadContext();
  109. friend void RpcpSetThreadContext(void * Context);
  110. #ifdef RPC_OLD_IO_PROTECTION
  111. long
  112. InqProtectCount (
  113. );
  114. #endif
  115. void
  116. CommonConstructor (
  117. );
  118. RPC_STATUS
  119. SetCancelTimeout (
  120. IN long Timeout
  121. );
  122. BOOL
  123. IsSyncCall (
  124. ) {return !fAsync;}
  125. BOOL
  126. IsIOPending();
  127. void
  128. SetExtendedError (
  129. IN RPC_STATUS Status
  130. )
  131. {
  132. ExtendedStatus = Status;
  133. }
  134. RPC_STATUS
  135. GetExtendedError (
  136. )
  137. {
  138. return ExtendedStatus;
  139. }
  140. RPC_STATUS
  141. CancelCall (
  142. IN BOOL fTimeoutValid = FALSE,
  143. IN long Timeout = 0
  144. );
  145. RPC_STATUS
  146. RegisterForCancels (
  147. IN CALL *Call
  148. );
  149. void
  150. UnregisterForCancels (
  151. );
  152. void
  153. YieldThread (
  154. )
  155. {
  156. LARGE_INTEGER TimeOut;
  157. PLARGE_INTEGER pTimeOut;
  158. NTSTATUS Status;
  159. if (GetYieldedFlag() == 0)
  160. {
  161. SetYieldedFlag();
  162. //
  163. // Sleep for the smallest possible time
  164. //
  165. TimeOut.QuadPart = Int32x32To64( 1, -1 );
  166. pTimeOut = &TimeOut;
  167. do
  168. {
  169. Status = NtDelayExecution(
  170. (BOOLEAN)FALSE,
  171. pTimeOut
  172. );
  173. } while (Status == STATUS_ALERTED);
  174. }
  175. }
  176. void
  177. ResetYield()
  178. {
  179. ClearYieldedFlag();
  180. }
  181. void
  182. PurgeEEInfo (
  183. void
  184. );
  185. inline ExtendedErrorInfo *
  186. GetEEInfo (
  187. void
  188. )
  189. {
  190. return ThreadEEInfo;
  191. }
  192. inline void
  193. SetEEInfo (
  194. ExtendedErrorInfo *NewEEInfo
  195. )
  196. {
  197. ThreadEEInfo = NewEEInfo;
  198. }
  199. inline void *
  200. GetNDRSlot (
  201. void
  202. )
  203. {
  204. return NDRSlot;
  205. }
  206. inline void
  207. SetNDRSlot (
  208. void *NewNDRSlot
  209. )
  210. {
  211. NDRSlot = NewNDRSlot;
  212. }
  213. inline LRPC_CCALL *
  214. GetCachedLrpcCall (
  215. void
  216. )
  217. {
  218. return CachedLrpcCall;
  219. }
  220. inline void
  221. SetCachedLrpcCall (
  222. LRPC_CCALL *NewCall
  223. )
  224. {
  225. CachedLrpcCall = NewCall;
  226. }
  227. inline void *
  228. GetLastSuccessfullyDestroyedContext (
  229. void
  230. )
  231. {
  232. return LastSuccessfullyDestroyedContext;
  233. }
  234. inline void
  235. SetLastSuccessfullyDestroyedContext (
  236. void *NewLastSuccessfullyDestroyedContext
  237. )
  238. {
  239. LastSuccessfullyDestroyedContext = NewLastSuccessfullyDestroyedContext;
  240. }
  241. void
  242. GetWaiterCache (
  243. OUT SWMRWaiter **WaiterCache,
  244. IN SCALL *SCall,
  245. IN SWMRWaiterType WaiterType
  246. );
  247. void
  248. FreeWaiterCache (
  249. IN OUT SWMRWaiter **WaiterCache
  250. );
  251. inline void
  252. SetCachedEEInfoBlock (
  253. IN ExtendedErrorInfo *EEInfoBlock,
  254. IN ULONG NumberOfParamsInBlock
  255. )
  256. {
  257. if (CachedEEInfoBlock == NULL)
  258. {
  259. CachedEEInfoBlock = EEInfoBlock;
  260. ParametersOfCachedEEInfo = NumberOfParamsInBlock;
  261. }
  262. else if (NumberOfParamsInBlock > ParametersOfCachedEEInfo)
  263. {
  264. // we have an incoming block larger than the cache - keep
  265. // the larger and throw away the smaller
  266. FreeEEInfoRecordShallow(CachedEEInfoBlock);
  267. CachedEEInfoBlock = EEInfoBlock;
  268. ParametersOfCachedEEInfo = NumberOfParamsInBlock;
  269. }
  270. else
  271. {
  272. FreeEEInfoRecordShallow(EEInfoBlock);
  273. }
  274. }
  275. inline ExtendedErrorInfo *
  276. GetCachedEEInfoBlock (
  277. IN ULONG NumberOfParamsInBlock
  278. )
  279. {
  280. ExtendedErrorInfo *LocalEEInfo = NULL;
  281. if (CachedEEInfoBlock && (NumberOfParamsInBlock <= ParametersOfCachedEEInfo))
  282. {
  283. // N.B. Here we can get gradual degradation of the cached block
  284. // as we take out a larger block, but we return a block whose
  285. // size we think is only the number of used parameters. For example,
  286. // if we have in the cache block with 4 parameters, and we take
  287. // it out, and we use it on record with 2 parameters, we will
  288. // return the block through SetCachedEEInfoBlock as a 2-parameter
  289. // block. This means that the next time we need 4 parameters, we
  290. // may go to the heap, even though we have a large enough block
  291. // in the thread cache. That's ok. The way to avoid this is to keep
  292. // the real size of the block in the eeinfo record, which is too
  293. // big a waste of space and code. The current method handles the
  294. // Exchange server too busy error, which is the main consumer of
  295. // this cache
  296. LocalEEInfo = CachedEEInfoBlock;
  297. CachedEEInfoBlock = NULL;
  298. ParametersOfCachedEEInfo = 0;
  299. }
  300. return LocalEEInfo;
  301. }
  302. inline void
  303. SetDestroyedWithOutstandingLocksFlag (
  304. void
  305. )
  306. {
  307. Flags.SetFlagUnsafe(CallDestroyedWithOutstandingLocks);
  308. }
  309. inline BOOL
  310. GetDestroyedWithOutstandingLocksFlag (
  311. void
  312. )
  313. {
  314. return Flags.GetFlag(CallDestroyedWithOutstandingLocks);
  315. }
  316. inline void
  317. ClearDestroyedWithOutstandingLocksFlag (
  318. void
  319. )
  320. {
  321. Flags.ClearFlagUnsafe(CallDestroyedWithOutstandingLocks);
  322. }
  323. inline void
  324. SetCallCancelledFlag (
  325. void
  326. )
  327. {
  328. Flags.SetFlagUnsafe(CallCancelled);
  329. }
  330. inline BOOL
  331. GetCallCancelledFlag (
  332. void
  333. )
  334. {
  335. return Flags.GetFlag(CallCancelled);
  336. }
  337. inline void
  338. ClearCallCancelledFlag (
  339. void
  340. )
  341. {
  342. Flags.ClearFlagUnsafe(CallCancelled);
  343. }
  344. inline void
  345. SetYieldedFlag (
  346. void
  347. )
  348. {
  349. Flags.SetFlagUnsafe(Yielded);
  350. }
  351. inline BOOL
  352. GetYieldedFlag (
  353. void
  354. )
  355. {
  356. return Flags.GetFlag(Yielded);
  357. }
  358. inline void
  359. ClearYieldedFlag (
  360. void
  361. )
  362. {
  363. Flags.ClearFlagUnsafe(Yielded);
  364. }
  365. };
  366. inline BOOL
  367. THREAD::IsIOPending()
  368. {
  369. NTSTATUS Status;
  370. BOOL IsIoPending;
  371. Status = NtQueryInformationThread(
  372. HandleToThread,
  373. ThreadIsIoPending,
  374. &IsIoPending,
  375. sizeof(IsIoPending),
  376. NULL
  377. );
  378. return (NT_SUCCESS(Status) && IsIoPending);
  379. }
  380. extern THREAD_IDENTIFIER
  381. GetThreadIdentifier (
  382. );
  383. extern void PauseExecution(unsigned long time);
  384. // This class represents a dynamic link library. When it is constructed,
  385. // the dll is loaded, and when it is destructed, the dll is unloaded.
  386. // The only operation is obtaining the address of an entry point into
  387. // the dll.
  388. class DLL
  389. {
  390. private:
  391. void * DllHandle;
  392. public:
  393. DLL (
  394. IN RPC_CHAR * DllName,
  395. OUT RPC_STATUS * Status
  396. );
  397. ~DLL (
  398. );
  399. void *
  400. GetEntryPoint (
  401. IN char * Procedure
  402. );
  403. };
  404. extern int
  405. InitializeThreads (
  406. );
  407. extern void
  408. UninitializeThreads (
  409. );
  410. extern RPC_STATUS
  411. SetThreadStackSize (
  412. IN unsigned long ThreadStackSize
  413. );
  414. extern long
  415. ThreadGetRpcCancelTimeout(
  416. );
  417. extern void
  418. ThreadSetRpcCancelTimeout(
  419. long Timeout
  420. );
  421. RPC_STATUS
  422. RegisterForCancels(
  423. CALL * Call
  424. );
  425. RPC_STATUS
  426. UnregisterForCancels(
  427. );
  428. RPC_STATUS
  429. RpcpThreadCancel(
  430. void * ThreadHandle
  431. );
  432. BOOL
  433. ThreadCancelsEnabled (
  434. );
  435. VOID RPC_ENTRY
  436. CancelAPCRoutine (
  437. ULONG_PTR Timeout
  438. );
  439. VOID RPC_ENTRY
  440. CancelExAPCRoutine (
  441. ULONG_PTR Timeout
  442. );
  443. RPC_STATUS
  444. RpcpGetThreadPointerFromHandle(
  445. void * ThreadHandle,
  446. THREAD * * pThread
  447. );
  448. inline THREAD *
  449. RpcpGetThreadPointer(
  450. )
  451. {
  452. return (THREAD *) NtCurrentTeb()->ReservedForNtRpc;
  453. }
  454. inline void
  455. RpcpSetThreadPointer(
  456. THREAD * Thread
  457. )
  458. {
  459. NtCurrentTeb()->ReservedForNtRpc = Thread;
  460. }
  461. inline THREAD_IDENTIFIER
  462. GetThreadIdentifier (
  463. )
  464. {
  465. return(NtCurrentTeb()->ClientId.UniqueThread);
  466. }
  467. #pragma optimize ("t", on)
  468. inline void
  469. RpcpPurgeEEInfoFromThreadIfNecessary (
  470. IN THREAD *ThisThread
  471. )
  472. {
  473. if (ThisThread->ThreadEEInfo)
  474. ThisThread->PurgeEEInfo();
  475. }
  476. #pragma optimize("", on)
  477. inline void
  478. RpcpPurgeEEInfo (
  479. void
  480. )
  481. {
  482. THREAD *ThisThread = RpcpGetThreadPointer();
  483. ASSERT(ThisThread);
  484. RpcpPurgeEEInfoFromThreadIfNecessary(ThisThread);
  485. }
  486. inline ExtendedErrorInfo *
  487. RpcpGetEEInfo (
  488. void
  489. )
  490. {
  491. THREAD *ThisThread = RpcpGetThreadPointer();
  492. ASSERT(ThisThread);
  493. return ThisThread->GetEEInfo();
  494. }
  495. inline void
  496. RpcpSetEEInfoForThread (
  497. THREAD *ThisThread,
  498. ExtendedErrorInfo *EEInfo
  499. )
  500. {
  501. ASSERT(ThisThread->GetEEInfo() == NULL);
  502. ThisThread->SetEEInfo(EEInfo);
  503. }
  504. inline void
  505. RpcpSetEEInfo (
  506. ExtendedErrorInfo *EEInfo
  507. )
  508. {
  509. THREAD *ThisThread = RpcpGetThreadPointer();
  510. ASSERT(ThisThread);
  511. RpcpSetEEInfoForThread(ThisThread, EEInfo);
  512. }
  513. inline void
  514. RpcpClearEEInfoForThread (
  515. THREAD *ThisThread
  516. )
  517. {
  518. ThisThread->SetEEInfo(NULL);
  519. }
  520. inline void
  521. RpcpClearEEInfo (
  522. void
  523. )
  524. {
  525. THREAD *ThisThread = RpcpGetThreadPointer();
  526. ASSERT(ThisThread);
  527. RpcpClearEEInfoForThread(ThisThread);
  528. }
  529. inline RPC_STATUS
  530. RpcpSetNDRSlot (
  531. IN void *NewSlot
  532. )
  533. {
  534. THREAD *ThisThread = ThreadSelf();
  535. if (ThisThread == NULL)
  536. return RPC_S_OUT_OF_MEMORY;
  537. ThisThread->SetNDRSlot(NewSlot);
  538. return RPC_S_OK;
  539. }
  540. inline void *
  541. RpcpGetNDRSlot (
  542. void
  543. )
  544. {
  545. THREAD *ThisThread = RpcpGetThreadPointer();
  546. ASSERT(ThisThread);
  547. return ThisThread->GetNDRSlot();
  548. }
  549. THREAD *
  550. ThreadSelfHelper (
  551. );
  552. #pragma optimize ("t", on)
  553. inline THREAD *
  554. ThreadSelf (
  555. )
  556. {
  557. RPC_STATUS Status;
  558. THREAD * Thread = RpcpGetThreadPointer();
  559. if (Thread)
  560. {
  561. return Thread;
  562. }
  563. return(ThreadSelfHelper());
  564. }
  565. #pragma optimize("", on)
  566. inline void *
  567. RpcpGetThreadContext (
  568. )
  569. {
  570. THREAD * Thread = ThreadSelf();
  571. if (Thread == 0)
  572. {
  573. return(0);
  574. }
  575. return(Thread->Context);
  576. }
  577. inline void
  578. RpcpSetThreadContextWithThread (
  579. IN THREAD *ThisThread,
  580. IN void * Context
  581. )
  582. {
  583. ThisThread->Context = Context;
  584. ThisThread->fAsync = FALSE;
  585. }
  586. inline void
  587. RpcpSetThreadContext (
  588. IN void * Context
  589. )
  590. {
  591. THREAD *Thread = RpcpGetThreadPointer();
  592. RpcpSetThreadContextWithThread(Thread, Context);
  593. }
  594. void
  595. SetExtendedError(
  596. IN RPC_STATUS Status
  597. );
  598. #endif // __THREADS__