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.

481 lines
14 KiB

  1. /***************************************************************************\
  2. *
  3. * File: Context.cpp
  4. *
  5. * Description:
  6. * This file implements the main Context used by the ResourceManager to manage
  7. * independent "work contexts".
  8. *
  9. *
  10. * History:
  11. * 4/18/2000: JStall: Created
  12. *
  13. * Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
  14. *
  15. \***************************************************************************/
  16. #include "stdafx.h"
  17. #include "Services.h"
  18. #include "Context.h"
  19. #include "Thread.h"
  20. #include "ResourceManager.h"
  21. #if !USE_DYNAMICTLS
  22. __declspec(thread) Context * t_pContext;
  23. #endif
  24. /***************************************************************************\
  25. *****************************************************************************
  26. *
  27. * class Context
  28. *
  29. *****************************************************************************
  30. \***************************************************************************/
  31. //------------------------------------------------------------------------------
  32. Context::Context()
  33. {
  34. //
  35. // Immediately attach this Context to the Thread object. This is required
  36. // because creation of the Context may need the Thread (for example, to
  37. // create the Parking Container). If something fails during Context
  38. // creation or later, the new Thread will be unlocked, destroying this new
  39. // Context with it.
  40. //
  41. GetThread()->SetContext(this);
  42. #if DBG
  43. m_DEBUG_pthrLock = NULL;
  44. #endif // DBG
  45. }
  46. //------------------------------------------------------------------------------
  47. Context::~Context()
  48. {
  49. #if DBG_CHECK_CALLBACKS
  50. if (m_cLiveCallbacks > 0) {
  51. AutoTrace("DirectUser Context: 0x%p\n", this);
  52. AlwaysPromptInvalid("Can not destroy a Context while inside a callback");
  53. }
  54. #endif
  55. //
  56. // NOTE: The Context (and its SubContexts) can be destroyed on a different
  57. // thread during destruction. It is advisable to allocate any dangling data
  58. // on the Process heap so that it can be safely destroyed at this time.
  59. //
  60. //
  61. // First, tear down the sub-contexts since they may rely on shared resources
  62. // such as the heap.
  63. //
  64. // NOTE: We need to destroy the SubContext's in multiple stages so that they
  65. // can refer to each other during destruction. This provides an opportunity
  66. // for any callbacks to occur during the "pre-destroy" stage. We
  67. // temporarily need to increment the lock count while we pre-destroy the
  68. // SubContext's because they may callback. During these callbacks, the
  69. // application may call API's to cleanup objects in the Context.
  70. //
  71. for (int idx = 0; idx < slCOUNT; idx++) {
  72. if (m_rgSCs[idx] != NULL) {
  73. ProcessDelete(SubContext, m_rgSCs[idx]);
  74. m_rgSCs[idx] = NULL;
  75. }
  76. }
  77. #if DBG_CHECK_CALLBACKS
  78. if (m_cLiveObjects > 0) {
  79. AutoTrace("DirectUser Context: 0x%p\n", this);
  80. AlwaysPromptInvalid("Outstanding DirectUser objects after Context shutdown");
  81. }
  82. #endif
  83. //
  84. // Tear down low-level resources (such as the heap)
  85. //
  86. if (m_pHeap != NULL) {
  87. DestroyContextHeap(m_pHeap);
  88. }
  89. //
  90. // Finally, detach this Context from the Thread. This must be done here
  91. // since the Context is created in Context::Build() and must be fully
  92. // detached from the Thread if any stage of construction fails.
  93. //
  94. GetThread()->SetContext(NULL);
  95. }
  96. /***************************************************************************\
  97. *
  98. * Context::xwDestroy
  99. *
  100. * xwDestroy() is called to finally delete the object.
  101. *
  102. \***************************************************************************/
  103. void
  104. Context::xwDestroy()
  105. {
  106. ProcessDelete(Context, this);
  107. }
  108. /***************************************************************************\
  109. *
  110. * Context::xwPreDestroyNL
  111. *
  112. * xwPreDestroyNL() is called by a Thread when the Context is about to be
  113. * destroyed, but before the SubTreads have been destroyed.
  114. *
  115. \***************************************************************************/
  116. void
  117. Context::xwPreDestroyNL()
  118. {
  119. AssertMsg(m_cRef == 0, "Locks must initially be at 0 to be destroyed");
  120. m_cRef++;
  121. for (int idx = 0; idx < slCOUNT; idx++) {
  122. if (m_rgSCs[idx] != NULL) {
  123. m_rgSCs[idx]->xwPreDestroyNL();
  124. }
  125. }
  126. m_cRef--;
  127. AssertMsg(m_cRef == 0, "Locks should be 0 after callbacks");
  128. }
  129. /***************************************************************************\
  130. *
  131. * Context::Build
  132. *
  133. * Build() creates a new, fully initialized Context instance.
  134. *
  135. * NOTE: This function is designed to be called from the ResourceManager
  136. * and should not normally be called directly.
  137. *
  138. * <error> E_OUTOFMEMORY</>
  139. * <error> E_NOTIMPL</>
  140. * <error> E_INVALIDARG</>
  141. *
  142. \***************************************************************************/
  143. HRESULT
  144. Context::Build(
  145. IN INITGADGET * pInit, // Context description
  146. IN DUserHeap * pHeap, // Context heap to use
  147. OUT Context ** ppctxNew) // Newly created Context
  148. {
  149. #if USE_DYNAMICTLS
  150. AssertMsg(!IsInitContext(), "Only call on uninitialized Context's");
  151. #else
  152. AssertMsg(t_pContext == NULL, "Only call on uninitialized Context's");
  153. #endif
  154. Context * pContext = NULL;
  155. HRESULT hr = E_INVALIDARG;
  156. //
  157. // Create a new Context and initialize low-level resources that other
  158. // initialization requires (such as a heap).
  159. //
  160. pContext = ProcessNew(Context);
  161. if (pContext == NULL) {
  162. hr = E_OUTOFMEMORY;
  163. goto ErrorExit;
  164. }
  165. AssertMsg(pHeap != NULL, "Must specify a valid heap");
  166. pContext->m_pHeap = pHeap;
  167. pContext->m_nThreadMode = pInit->nThreadMode;
  168. pContext->m_nPerfMode = pInit->nPerfMode;
  169. if ((pContext->m_nPerfMode == IGPM_BLEND) && IsRemoteSession()) {
  170. //
  171. // For "blend" models, if we are running as a TS session, optimize for
  172. // size.
  173. //
  174. pContext->m_nPerfMode = IGPM_SIZE;
  175. }
  176. BOOL fThreadSafe;
  177. switch (pInit->nThreadMode)
  178. {
  179. case IGTM_SINGLE:
  180. case IGTM_SEPARATE:
  181. fThreadSafe = FALSE;
  182. break;
  183. default:
  184. fThreadSafe = TRUE;
  185. }
  186. pContext->m_lock.SetThreadSafe(fThreadSafe);
  187. //
  188. // Initialize each of the sub-contexts. These can safely use the heap
  189. // which has already been initialized. We need to grab a ContextLock
  190. // during this since we may make callbacks during construction of a
  191. // Context.
  192. //
  193. #if !USE_DYNAMICTLS
  194. t_pContext = pContext; // SubContext's may need to grab the Context
  195. #endif
  196. {
  197. ContextLock cl;
  198. Verify(cl.LockNL(ContextLock::edDefer, pContext));
  199. for (int idx = 0; idx < slCOUNT; idx++) {
  200. ContextPackBuilder * pBuilder = ContextPackBuilder::GetBuilder((Context::ESlot) idx);
  201. AssertMsg(pBuilder != NULL, "Builder not initialized using INIT_SUBCONTEXT");
  202. pContext->m_rgSCs[idx] = pBuilder->New(pContext);
  203. if (pContext->m_rgSCs[idx] == NULL) {
  204. hr = E_OUTOFMEMORY;
  205. goto ErrorExit;
  206. }
  207. hr = pContext->m_rgSCs[idx]->Create(pInit);
  208. if (FAILED(hr)) {
  209. #if !USE_DYNAMICTLS
  210. t_pContext = NULL;
  211. #endif
  212. goto ErrorExit;
  213. }
  214. }
  215. }
  216. AssertMsg(pContext != NULL, "Ensure Context is valid");
  217. *ppctxNew = pContext;
  218. return S_OK;
  219. ErrorExit:
  220. AssertMsg(FAILED(hr), "Must specify failure");
  221. //
  222. // Something went wrong while creating a new context, so need to tear it
  223. // down.
  224. //
  225. // NOTE: We CAN NOT use xwUnlock() or xwDeleteHandle(), since these are
  226. // intercepted and would go through the ResourceManager. Instead, we need
  227. // bump down the ref count, pre-destroy the Context, and delete it.
  228. //
  229. if (pContext != NULL) {
  230. VerifyMsg(--pContext->m_cRef == 0, "Should only have initial reference");
  231. pContext->xwPreDestroyNL();
  232. ProcessDelete(Context, pContext);
  233. }
  234. *ppctxNew = NULL;
  235. return hr;
  236. }
  237. /***************************************************************************\
  238. *
  239. * Context::xwDeleteHandle
  240. *
  241. * xwDeleteHandle() is called from ::DeleteHandle() to destroy an object and
  242. * free its associated resources. This function must be called on the same
  243. * thread as originally created the Context so that the corresponding Thread
  244. * object can also be destroyed.
  245. *
  246. \***************************************************************************/
  247. BOOL
  248. Context::xwDeleteHandle()
  249. {
  250. #if DBG
  251. AssertMsg(IsInitThread(), "Thread must be initialized to destroy the Context");
  252. Context * pctxThread = GetThread()->GetContext();
  253. AssertMsg(pctxThread == this, "Thread currently running on should match the Context being destroyed");
  254. #endif // DBG
  255. #if DBG_CHECK_CALLBACKS
  256. if (m_cLiveCallbacks > 0) {
  257. AutoTrace("DirectUser Context: 0x%p\n", this);
  258. AlwaysPromptInvalid("Can not DeleteHandle(Context) while inside a callback");
  259. }
  260. #endif
  261. //
  262. // We have NOT taken a ContextLock when calling DeleteHandle() on the
  263. // Context. Therefore, we are actually an NL function, but the virtual
  264. // function can't be renamed.
  265. //
  266. ResourceManager::xwNotifyThreadDestroyNL();
  267. return FALSE;
  268. }
  269. /***************************************************************************\
  270. *
  271. * Context::AddCurrentThread
  272. *
  273. * AddCurrentThread() sets the current thread to use the specified Context.
  274. *
  275. * NOTE: This function is designed to be called from the ResourceManager
  276. * and should not normally be called directly.
  277. *
  278. \***************************************************************************/
  279. void
  280. Context::AddCurrentThread()
  281. {
  282. #if USE_DYNAMICTLS
  283. AssertMsg(!IsInitContext(), "Ensure Context is not already set");
  284. #else
  285. AssertMsg(t_pContext == NULL, "Ensure Context is not already set");
  286. #endif
  287. GetThread()->SetContext(this);
  288. }
  289. /***************************************************************************\
  290. *
  291. * Context::xwOnIdleNL
  292. *
  293. * xwOnIdleNL() cycles through all of the SubContext's, giving each an
  294. * opportunity to perform any idle-time processing. This is time when there
  295. * are no more messages to process. Each SubContext can also return a
  296. * "delay" count that specifies how long it will have before more processing.
  297. *
  298. \***************************************************************************/
  299. DWORD
  300. Context::xwOnIdleNL()
  301. {
  302. DWORD dwTimeOut = INFINITE;
  303. AssertMsg(dwTimeOut == 0xFFFFFFFF, "Ensure largest delay");
  304. for (int idx = 0; idx < slCOUNT; idx++) {
  305. DWORD dwNewTimeOut = m_rgSCs[idx]->xwOnIdleNL();
  306. if (dwNewTimeOut < dwTimeOut) {
  307. dwTimeOut = dwNewTimeOut;
  308. }
  309. }
  310. return dwTimeOut;
  311. }
  312. #if DBG
  313. //------------------------------------------------------------------------------
  314. void
  315. Context::DEBUG_AssertValid() const
  316. {
  317. if (IsOrphanedNL()) {
  318. PromptInvalid("Illegally using an orphaned Context");
  319. AssertMsg(0, "API layer let an Orphaned Context in");
  320. }
  321. if (m_DEBUG_tidLock != 0) {
  322. Assert(m_DEBUG_pthrLock != NULL);
  323. }
  324. Assert(m_pHeap != NULL);
  325. for (int idx = 0; idx < slCOUNT; idx++) {
  326. AssertInstance(m_rgSCs[idx]);
  327. }
  328. }
  329. #endif
  330. /***************************************************************************\
  331. *****************************************************************************
  332. *
  333. * class ContextPackBuilder
  334. *
  335. *****************************************************************************
  336. \***************************************************************************/
  337. PREINIT_SUBCONTEXT(CoreSC);
  338. PREINIT_SUBCONTEXT(MotionSC);
  339. ContextPackBuilder * ContextPackBuilder::s_rgBuilders[Context::slCOUNT] =
  340. {
  341. INIT_SUBCONTEXT(CoreSC),
  342. INIT_SUBCONTEXT(MotionSC),
  343. };
  344. /***************************************************************************\
  345. *****************************************************************************
  346. *
  347. * class SubContext
  348. *
  349. *****************************************************************************
  350. \***************************************************************************/
  351. #if DBG
  352. //------------------------------------------------------------------------------
  353. void
  354. SubContext::DEBUG_AssertValid() const
  355. {
  356. // Don't use AssertInstance since it would be recursive.
  357. Assert(m_pParent != NULL);
  358. }
  359. #endif
  360. /***************************************************************************\
  361. *****************************************************************************
  362. *
  363. * class ContextLock
  364. *
  365. *****************************************************************************
  366. \***************************************************************************/
  367. //------------------------------------------------------------------------------
  368. BOOL
  369. ContextLock::LockNL(ContextLock::EnableDefer ed, Context * pctxThread)
  370. {
  371. AssertMsg(pctx == NULL, "Can only Lock() once");
  372. AssertMsg(pctxThread != NULL, "Must specify a valid Context to lock");
  373. //
  374. // Check if the Context has been orphaned __before__ entering the lock so
  375. // that we access as few members as possible.
  376. //
  377. if (pctxThread->IsOrphanedNL()) {
  378. PromptInvalid("Illegally using an orphaned Context");
  379. return FALSE;
  380. }
  381. pctx = pctxThread;
  382. pctx->Enter();
  383. pctx->EnableDefer(ed, &fOldDeferred);
  384. return TRUE;
  385. }