Source code of Windows XP (NT5)
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.

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