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.

3056 lines
90 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: handtabl.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Implements the USER handle table.
  7. *
  8. * 01-13-92 ScottLu Created.
  9. \***************************************************************************/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #pragma alloc_text(INIT, HMInitHandleTable)
  13. #if DBG
  14. #define HTIENTRY(szObjectType, structName, fnDestroy, dwAllocTag, bObjectCreateFlags) \
  15. {szObjectType, sizeof(structName), (FnDestroyUserObject)fnDestroy, (CONST DWORD)dwAllocTag, (CONST BYTE)(bObjectCreateFlags)}
  16. #define HTIENTRY_VARIABLESIZE(szObjectType, dwSize, fnDestroy, dwAllocTag, bObjectCreateFlags) \
  17. {szObjectType, dwSize, (FnDestroyUserObject)fnDestroy, (CONST DWORD)dwAllocTag, (CONST BYTE)(bObjectCreateFlags)}
  18. #else // DBG
  19. #define HTIENTRY(szObjectType, structName, fnDestroy, dwAllocTag, bObjectCreateFlags) \
  20. {(FnDestroyUserObject)fnDestroy, (CONST DWORD)dwAllocTag, (CONST BYTE)(bObjectCreateFlags)}
  21. #define HTIENTRY_VARIABLESIZE(szObjectType, dwSize, fnDestroy, dwAllocTag, bObjectCreateFlags) \
  22. {(FnDestroyUserObject)fnDestroy, (CONST DWORD)dwAllocTag, (CONST BYTE)(bObjectCreateFlags)}
  23. #endif // DBG
  24. VOID HMNullFnDestroy(
  25. PVOID pobj)
  26. {
  27. RIPMSG1(RIP_WARNING, "HM: No clean up function for 0x%p", pobj);
  28. HMDestroyObject(pobj);
  29. }
  30. /***************************************************************************\
  31. *
  32. * Table of user objects statistics. Used by userkdx.dumhmgr debugger extension
  33. *
  34. \***************************************************************************/
  35. #if DBG
  36. PERFHANDLEINFO gaPerfhti[TYPE_CTYPES]; /* stores current counts */
  37. PERFHANDLEINFO gaPrevhti[TYPE_CTYPES]; /* stores previous counts */
  38. #endif // DBG
  39. #if DBG || FRE_LOCK_RECORD
  40. DWORD gdwLockRecordFlags;
  41. BOOL RecordLockThisType(
  42. PVOID pobj)
  43. {
  44. BOOL bRecord;
  45. PHE phe = HMPheFromObject(pobj);
  46. bRecord = (gdwLockRecordFlags & (1 << (phe->bType)));
  47. return bRecord;
  48. }
  49. #endif
  50. /***************************************************************************\
  51. *
  52. * Table of handle type information.
  53. *
  54. * Desktop and Shared Heap objects can't be tagged as yet
  55. * (TAG_WINDOW is bogus for heap windows, but not for desktop and other
  56. * windows allocated in pool).
  57. *
  58. * WARNING: Keep it in sync with aszTypeNames table from ntuser\kdexts\userexts.c
  59. *
  60. * All HM objects must start with a HEAD structure. In addition:
  61. * (If you find these comments to be wrong, please fix them)
  62. *
  63. * OCF_PROCESSOWNED: Object must start with a PROC*HEAD structure
  64. * A ptiOwner must be provided
  65. * The object affects the handle quota (ppi->UserHandleCount)
  66. * The object will be destroyed if the process goes away.
  67. *
  68. * OCF_MARKPROCESS: Object must start with a PROCMARKHEAD structure
  69. * A ptiOwner must be provided
  70. * It must not use OCF_DESKTOPHEAP (implementation limitation)
  71. *
  72. * OCF_THREADOWNED: Object must start with a THR*HEAD structure
  73. * The object affects the handle quota (ppi->UserHandleCount)
  74. * The object will be destroyed if the thread goes away.
  75. *
  76. * OCF_DESKTOPHEAP: Object must start with a *DESKHEAD structure
  77. * A pdeskSrc must be provided at allocation time
  78. * It must not use OCF_MARKPROCESS (implementation limitation)
  79. *
  80. \***************************************************************************/
  81. #if (TYPE_FREE != 0)
  82. #error TYPE_FREE must be zero.
  83. #endif
  84. CONST HANDLETYPEINFO gahti[TYPE_CTYPES] = {
  85. /* TYPE_FREE - HEAD */
  86. HTIENTRY("Free", HEAD,
  87. NULL,
  88. 0,
  89. 0),
  90. /* TYPE_WINDOW - WND(THRDESKHEAD) */
  91. HTIENTRY("Window", WND,
  92. xxxDestroyWindow,
  93. TAG_WINDOW,
  94. OCF_THREADOWNED | OCF_USEPOOLQUOTA | OCF_DESKTOPHEAP | OCF_USEPOOLIFNODESKTOP | OCF_VARIABLESIZE),
  95. /* TYPE_MENU - MENU(PROCDESKHEAD) */
  96. HTIENTRY("Menu", MENU,
  97. _DestroyMenu,
  98. 0,
  99. OCF_PROCESSOWNED | OCF_DESKTOPHEAP),
  100. /* TYPE_CURSOR - CURSOR(PROCMARKHEAD) or ACON(PROCMARKHEAD) */
  101. HTIENTRY("Icon/Cursor", CURSOR,
  102. DestroyUnlockedCursor,
  103. TAG_CURSOR,
  104. OCF_PROCESSOWNED | OCF_MARKPROCESS | OCF_USEPOOLQUOTA),
  105. /* TYPE_SETWINDOWPOS - SMWP(HEAD) */
  106. HTIENTRY("WPI(SWP) structure", SMWP,
  107. DestroySMWP,
  108. TAG_SWP,
  109. OCF_THREADOWNED | OCF_USEPOOLQUOTA),
  110. /* TYPE_HOOK - HOOK(THRDESKHEAD) */
  111. HTIENTRY("Hook", HOOK,
  112. FreeHook,
  113. 0,
  114. OCF_THREADOWNED | OCF_DESKTOPHEAP),
  115. /* TYPE_CLIPDATA - CLIPDATA(HEAD) */
  116. HTIENTRY("Clipboard Data", CLIPDATA,
  117. HMNullFnDestroy,
  118. TAG_CLIPBOARD,
  119. OCF_VARIABLESIZE),
  120. /* TYPE_CALLPROC - CALLPROCDATA(THRDESKHEAD) */
  121. HTIENTRY("CallProcData", CALLPROCDATA,
  122. HMDestroyObject,
  123. 0,
  124. OCF_PROCESSOWNED | OCF_DESKTOPHEAP),
  125. /* TYPE_ACCELTABLE - ACCELTABLE(PROCOBJHEAD) */
  126. HTIENTRY("Accelerator", ACCELTABLE,
  127. HMDestroyObject,
  128. TAG_ACCEL,
  129. OCF_PROCESSOWNED | OCF_USEPOOLQUOTA | OCF_VARIABLESIZE),
  130. /* TYPE_DDEACCESS - SVR_INSTANCE_INFO(THROBJHEAD) */
  131. HTIENTRY("DDE access", SVR_INSTANCE_INFO,
  132. HMNullFnDestroy,
  133. TAG_DDE9,
  134. OCF_THREADOWNED | OCF_USEPOOLQUOTA),
  135. /* TYPE_DDECONV - DDECONV(THROBJHEAD) */
  136. HTIENTRY("DDE conv", DDECONV,
  137. FreeDdeConv,
  138. TAG_DDEa,
  139. OCF_THREADOWNED | OCF_USEPOOLQUOTA),
  140. /* TYPE_DDEXACT - XSTATE(THROBJHEAD) */
  141. HTIENTRY("DDE Transaction", XSTATE,
  142. FreeDdeXact,
  143. TAG_DDEb,
  144. OCF_THREADOWNED | OCF_USEPOOLQUOTA),
  145. /* TYPE_MONITOR - MONITOR(HEAD) */
  146. HTIENTRY("Monitor", MONITOR,
  147. DestroyMonitor,
  148. TAG_DISPLAYINFO,
  149. OCF_SHAREDHEAP),
  150. /* TYPE_KBDLAYOUT - KL(HEAD) */
  151. HTIENTRY("Keyboard Layout", KL,
  152. DestroyKL,
  153. TAG_KBDLAYOUT,
  154. 0),
  155. /* TYPE_KBDFILE - KBDFILE(HEAD) */
  156. HTIENTRY("Keyboard File", KBDFILE,
  157. DestroyKF,
  158. TAG_KBDFILE,
  159. 0),
  160. /* TYPE_WINEVENTHOOK - EVENTHOOK(THROBJHEAD) */
  161. HTIENTRY("WinEvent hook", EVENTHOOK,
  162. DestroyEventHook,
  163. TAG_WINEVENT,
  164. OCF_THREADOWNED),
  165. /* TYPE_TIMER - TIMER(HEAD) */
  166. HTIENTRY("Timer", TIMER,
  167. FreeTimer,
  168. TAG_TIMER,
  169. 0),
  170. /* TYPE_INPUTCONTEXT - IMC(THRDESKHEAD) */
  171. HTIENTRY("Input Context", IMC,
  172. FreeInputContext,
  173. TAG_IME,
  174. OCF_THREADOWNED | OCF_DESKTOPHEAP),
  175. #ifdef GENERIC_INPUT
  176. /* TYPE_HIDDATA - HIDDATA(THROBJHEAD) */
  177. HTIENTRY_VARIABLESIZE("HID Raw Data",
  178. FIELD_OFFSET(HIDDATA, rid.data.hid.bRawData),
  179. FreeHidData,
  180. TAG_HIDDATA,
  181. OCF_THREADOWNED | OCF_VARIABLESIZE),
  182. /* TYPE_DEVICEINFO - DEVICEINFO(HEAD) */
  183. HTIENTRY("Device Info", GENERIC_DEVICE_INFO,
  184. FreeDeviceInfo,
  185. TAG_DEVICEINFO,
  186. OCF_VARIABLESIZE),
  187. #endif // GENERIC_INPUT
  188. };
  189. /*
  190. * Handle table allocation globals. The purpose of keeping per-page free
  191. * lists is to keep the table as small as is practical and to minimize
  192. * the number of pages touched while performing handle table operations.
  193. */
  194. #define CPAGEENTRIESINIT 4
  195. DWORD gcHandlePages;
  196. PHANDLEPAGE gpHandlePages;
  197. #if DBG || FRE_LOCK_RECORD
  198. PPAGED_LOOKASIDE_LIST LockRecordLookaside;
  199. NTSTATUS InitLockRecordLookaside(VOID);
  200. VOID FreeLockRecord(PLR plr);
  201. VOID InitGlobalThreadLockArray(DWORD dwIndex);
  202. VOID ShowLocks(PHE);
  203. #endif
  204. VOID HMDestroyUnlockedObject(PHE phe);
  205. VOID HMRecordLock(PVOID ppobj, PVOID pobj, DWORD cLockObj);
  206. BOOL HMUnrecordLock(PVOID ppobj, PVOID pobj);
  207. /***************************************************************************\
  208. * DBGValidateHandleQuota
  209. *
  210. * 11-19-97 GerardoB Created.
  211. \***************************************************************************/
  212. #ifdef VALIDATEHANDLEQUOTA
  213. VOID DBGValidateHandleQuota(
  214. VOID)
  215. {
  216. BYTE bCreateFlags;
  217. DWORD dw;
  218. HANDLEENTRY * phe;
  219. PPROCESSINFO ppiT = gppiList;
  220. while (ppiT != NULL) {
  221. ppiT->lHandles = 0;
  222. ppiT = ppiT->ppiNextRunning;
  223. }
  224. phe = gSharedInfo.aheList;
  225. for (dw = 0; dw <= giheLast; dw++, phe++) {
  226. if (phe->bType == TYPE_FREE) {
  227. UserAssert(phe->pOwner == NULL);
  228. continue;
  229. }
  230. bCreateFlags = gahti[phe->bType].bObjectCreateFlags;
  231. if (bCreateFlags & OCF_PROCESSOWNED) {
  232. ((PPROCESSINFO)phe->pOwner)->lHandles++;
  233. continue;
  234. }
  235. if (bCreateFlags & OCF_THREADOWNED) {
  236. ((PTHREADINFO)phe->pOwner)->ppi->lHandles++;
  237. continue;
  238. }
  239. UserAssert(phe->pOwner == NULL);
  240. }
  241. ppiT = gppiList;
  242. while (ppiT != NULL) {
  243. UserAssert(ppiT->lHandles == ppiT->UserHandleCount);
  244. ppiT = ppiT->ppiNextRunning;
  245. }
  246. }
  247. #else
  248. #define DBGValidateHandleQuota()
  249. #endif
  250. /***************************************************************************\
  251. * DBGHMPheFromObject
  252. *
  253. * Validates and returns the HANDLEENTRY corresponding to a given object
  254. *
  255. * 09-23-97 GerardoB Created.
  256. \***************************************************************************/
  257. #if DBG
  258. PHE DBGHMPheFromObject(
  259. PVOID p)
  260. {
  261. PHE phe = _HMPheFromObject(p);
  262. UserAssert(phe->phead == p);
  263. UserAssert(_HMObjectFromHandle(phe->phead->h) == p);
  264. UserAssert(phe->wUniq == HMUniqFromHandle(phe->phead->h));
  265. UserAssert(phe->bType < TYPE_CTYPES);
  266. UserAssert((phe->pOwner != NULL)
  267. || !(gahti[phe->bType].bObjectCreateFlags & (OCF_PROCESSOWNED | OCF_THREADOWNED)));
  268. UserAssert(!(phe->bFlags & ~HANDLEF_VALID));
  269. return phe;
  270. }
  271. #endif
  272. /***************************************************************************\
  273. * DBGHMPheFromObject
  274. *
  275. * Validates and returns the object corresponding to a given handle.
  276. *
  277. * 09-23-97 GerardoB Created.
  278. \***************************************************************************/
  279. #if DBG
  280. PVOID DBGHMObjectFromHandle(
  281. HANDLE h)
  282. {
  283. PVOID p = _HMObjectFromHandle(h);
  284. UserAssert((h != NULL) ^ (p == NULL));
  285. if (p != NULL) {
  286. UserAssert(HMIndexFromHandle(((PHEAD)p)->h) == HMIndexFromHandle(h));
  287. UserAssert(p == HMRevalidateCatHandle(h));
  288. /*
  289. * This routine, unlike Validation, should return a real pointer if
  290. * the object exists, even if it is destroyed. But we should still
  291. * generate a warning.
  292. */
  293. if (HMPheFromObject(p)->bFlags & HANDLEF_DESTROY) {
  294. RIPMSGF1(RIP_WARNING, "Object p 0x%p is destroyed", p);
  295. }
  296. }
  297. return p;
  298. }
  299. PVOID DBGHMCatObjectFromHandle(
  300. HANDLE h)
  301. {
  302. /*
  303. * Note -- at this point, _HMObjectFromHandle does not check to see if
  304. * an object is destroyed.
  305. */
  306. PVOID p = _HMObjectFromHandle(h);
  307. UserAssert((h != NULL) ^ (p == NULL));
  308. if (p != NULL) {
  309. UserAssert(HMIndexFromHandle(((PHEAD)p)->h) == HMIndexFromHandle(h));
  310. UserAssert(p == HMRevalidateCatHandle(h));
  311. }
  312. return p;
  313. }
  314. #endif
  315. /***************************************************************************\
  316. * DBGPtoH and DBGPtoHq
  317. *
  318. * Validates and returns the handle corresponding to a given object
  319. *
  320. * 09-23-97 GerardoB Created.
  321. \***************************************************************************/
  322. #if DBG
  323. VOID DBGValidatePtoH(
  324. PVOID p,
  325. HANDLE h)
  326. {
  327. UserAssert((h != NULL) ^ (p == NULL));
  328. if (h != NULL) {
  329. UserAssert(p == HMRevalidateCatHandle(h));
  330. }
  331. }
  332. HANDLE DBGPtoH (PVOID p)
  333. {
  334. HANDLE h = _PtoH(p);
  335. DBGValidatePtoH(p, h);
  336. return h;
  337. }
  338. HANDLE DBGPtoHq (PVOID p)
  339. {
  340. HANDLE h;
  341. UserAssert(p != NULL);
  342. h = _PtoHq(p);
  343. DBGValidatePtoH(p, h);
  344. return h;
  345. }
  346. #endif
  347. /***************************************************************************\
  348. * DBGHW and DBGHWq
  349. *
  350. * Validates and returns the hwnd corresponding to a given pwnd.
  351. *
  352. * 09-23-97 GerardoB Created.
  353. \***************************************************************************/
  354. #if DBG
  355. VOID DBGValidateHW(
  356. PWND pwnd,
  357. HWND hwnd)
  358. {
  359. UserAssert((hwnd != NULL) ^ (pwnd == NULL));
  360. if (hwnd != NULL) {
  361. UserAssert(pwnd == HMValidateCatHandleNoSecure(hwnd, TYPE_WINDOW));
  362. }
  363. }
  364. PVOID DBGValidateHWCCX(
  365. PWND ccxPwnd,
  366. HWND hwnd,
  367. PTHREADINFO pti)
  368. {
  369. PVOID pobj = NULL;
  370. UserAssert((hwnd != NULL) ^ (ccxPwnd == NULL));
  371. if (hwnd != NULL) {
  372. pobj = HMValidateCatHandleNoSecureCCX(hwnd, TYPE_WINDOW, pti);
  373. UserAssert(ccxPwnd == pobj);
  374. }
  375. return pobj;
  376. }
  377. HWND DBGHW(
  378. PWND pwnd)
  379. {
  380. HWND hwnd = _HW(pwnd);
  381. DBGValidateHW(pwnd, hwnd);
  382. return hwnd;
  383. }
  384. HWND DBGHWCCX(
  385. PWND ccxPwnd)
  386. {
  387. HWND hwnd = _HWCCX(ccxPwnd);
  388. PWND pwndK = RevalidateHwnd(hwnd);
  389. PTHREADINFO pti = _GETPTI(pwndK);
  390. PWND pwnd = NULL;
  391. CheckCritIn();
  392. if (pwndK) {
  393. pwnd = (PWND) DBGValidateHWCCX(ccxPwnd, hwnd, pti);
  394. }
  395. if (pwnd == ccxPwnd) {
  396. if (!KeIsAttachedProcess()) {
  397. UserAssert(PpiCurrent() == _GETPTI(pwndK)->ppi);
  398. }
  399. }
  400. return hwnd;
  401. }
  402. HWND DBGHWq(
  403. PWND pwnd)
  404. {
  405. HWND hwnd;
  406. UserAssert(pwnd != NULL);
  407. hwnd = _HWq(pwnd);
  408. DBGValidateHW(pwnd, hwnd);
  409. return hwnd;
  410. }
  411. #endif
  412. /***************************************************************************\
  413. * DBGHMValidateFreeLists
  414. *
  415. * Walks all handle free lists to make sure all links are fine.
  416. *
  417. * 10/08/97 GerardoB Created
  418. \***************************************************************************/
  419. #if DBG
  420. VOID DBGHMValidateFreeList(
  421. ULONG_PTR iheFreeNext,
  422. BOOL fEven)
  423. {
  424. PHE phe;
  425. do {
  426. UserAssert(fEven ^ !!(iheFreeNext & 0x1));
  427. UserAssert(iheFreeNext < gpsi->cHandleEntries);
  428. phe = &gSharedInfo.aheList[iheFreeNext];
  429. UserAssert(phe->bType == TYPE_FREE);
  430. UserAssert(phe->pOwner == NULL);
  431. UserAssert(phe->bFlags == 0);
  432. iheFreeNext = (ULONG_PTR)phe->phead;
  433. } while (iheFreeNext != 0);
  434. }
  435. VOID DBGHMValidateFreeLists(
  436. VOID)
  437. {
  438. DWORD dw;
  439. PHANDLEPAGE php = gpHandlePages;
  440. for (dw = 0; dw < gcHandlePages; ++dw, ++php) {
  441. if (php->iheFreeEven != 0) {
  442. DBGHMValidateFreeList(php->iheFreeEven, TRUE);
  443. }
  444. if (php->iheFreeOdd != 0) {
  445. DBGHMValidateFreeList(php->iheFreeOdd, FALSE);
  446. }
  447. }
  448. }
  449. #else
  450. #define DBGHMValidateFreeLists()
  451. #endif
  452. #if DBG || FRE_LOCK_RECORD
  453. /***************************************************************************\
  454. * DbgDumpHandleTable
  455. *
  456. \***************************************************************************/
  457. DWORD DbgDumpHandleTable(
  458. VOID)
  459. {
  460. DWORD dw;
  461. PHE phe;
  462. DWORD dwHandles = 0;
  463. phe = gSharedInfo.aheList;
  464. if (phe == NULL) {
  465. KdPrint(("\nTERMSRV\nEmpty handle table\n"));
  466. return 0;
  467. }
  468. KdPrint(("\nTERMSRV\nDump the handle table\n"));
  469. KdPrint(("---------------------------------------------------\n"));
  470. KdPrint((" phead handle lock pOwner type flags\n"));
  471. KdPrint(("---------------------------------------------------\n"));
  472. for (dw = 0; dw <= giheLast; dw++, phe++) {
  473. if (phe->bType == TYPE_FREE) {
  474. UserAssert(phe->pOwner == NULL);
  475. continue;
  476. }
  477. KdPrint(("%04d %08x %08x %08d %08x %04x %05x\n",
  478. dwHandles++,
  479. phe->phead,
  480. phe->phead->h,
  481. phe->phead->cLockObj,
  482. phe->pOwner,
  483. phe->bType,
  484. phe->bFlags));
  485. }
  486. KdPrint(("----------------------------------------------\n"));
  487. KdPrint(("Number of handles left: %d\n", dwHandles));
  488. KdPrint(("End of handle table\n"));
  489. UserAssert(dwHandles == 0);
  490. return dwHandles;
  491. }
  492. /***************************************************************************\
  493. * HMCleanUpHandleTable
  494. *
  495. \***************************************************************************/
  496. VOID HMCleanUpHandleTable(
  497. VOID)
  498. {
  499. #if DBG
  500. DbgDumpHandleTable();
  501. #endif // DBG
  502. if (LockRecordLookaside != NULL) {
  503. ExDeletePagedLookasideList(LockRecordLookaside);
  504. UserFreePool(LockRecordLookaside);
  505. }
  506. }
  507. #endif // DBG
  508. /***************************************************************************\
  509. * HMInitHandleEntries
  510. *
  511. * 10/10/97 GerardoB Extracted from HMInitHandleTable and HMGrowHandleTable
  512. \***************************************************************************/
  513. VOID HMInitHandleEntries(
  514. ULONG_PTR iheFirstFree)
  515. {
  516. ULONG_PTR ihe;
  517. PHE pheT;
  518. /*
  519. * Zero out all the new entries
  520. */
  521. RtlZeroMemory (&gSharedInfo.aheList[iheFirstFree],
  522. (gpsi->cHandleEntries - iheFirstFree) * sizeof(HANDLEENTRY));
  523. /*
  524. * Link them together.
  525. * Each free odd/even entry points to the next odd/even free entry.
  526. */
  527. ihe = iheFirstFree;
  528. for (pheT = &gSharedInfo.aheList[ihe]; ihe < gpsi->cHandleEntries; ihe++, pheT++) {
  529. pheT->phead = (PHEAD)(ihe + 2);
  530. pheT->wUniq = 1;
  531. }
  532. /*
  533. * Terminate the lists.
  534. */
  535. if (gpsi->cHandleEntries > iheFirstFree) {
  536. UserAssert(pheT - 1 >= &gSharedInfo.aheList[iheFirstFree]);
  537. (pheT - 1)->phead = NULL;
  538. }
  539. if (gpsi->cHandleEntries > iheFirstFree + 1) {
  540. UserAssert(pheT - 2 >= &gSharedInfo.aheList[iheFirstFree]);
  541. (pheT - 2)->phead = NULL;
  542. }
  543. /*
  544. * Let's check that we got it right
  545. */
  546. DBGHMValidateFreeLists();
  547. }
  548. /***************************************************************************\
  549. * HMInitHandleTable
  550. *
  551. * Initialize the handle table. Unused entries are linked together.
  552. *
  553. * 01-13-92 ScottLu Created.
  554. \***************************************************************************/
  555. BOOL HMInitHandleTable(
  556. PVOID pReadOnlySharedSectionBase)
  557. {
  558. NTSTATUS Status;
  559. SIZE_T ulCommit;
  560. /*
  561. * Allocate the handle page array. Make it big enough for 4 pages, which
  562. * should be sufficient for nearly all instances.
  563. */
  564. gpHandlePages = UserAllocPool(CPAGEENTRIESINIT * sizeof(HANDLEPAGE),
  565. TAG_SYSTEM);
  566. if (gpHandlePages == NULL) {
  567. return FALSE;
  568. }
  569. #if DBG || FRE_LOCK_RECORD
  570. if (!NT_SUCCESS(InitLockRecordLookaside()))
  571. return FALSE;
  572. #endif
  573. /*
  574. * Allocate the array. We have the space from
  575. * NtCurrentPeb()->ReadOnlySharedMemoryBase to
  576. * NtCurrentPeb()->ReadOnlySharedMemoryHeap reserved for
  577. * the handle table. All we need to do is commit the pages.
  578. *
  579. * Compute the minimum size of the table. The allocation will
  580. * round this up to the next page size.
  581. */
  582. ulCommit = gpsi->cbHandleTable = PAGE_SIZE;
  583. Status = CommitReadOnlyMemory(ghSectionShared, &ulCommit, 0, NULL);
  584. if (!NT_SUCCESS(Status)) {
  585. return FALSE;
  586. }
  587. gSharedInfo.aheList = pReadOnlySharedSectionBase;
  588. gpsi->cHandleEntries = gpsi->cbHandleTable / sizeof(HANDLEENTRY);
  589. gcHandlePages = 1;
  590. /*
  591. * Initialize the handlepage info. Handle 0 is reserved so even free
  592. * list starts at 2.
  593. */
  594. gpHandlePages[0].iheFreeOdd = 1;
  595. gpHandlePages[0].iheFreeEven = 2;
  596. gpHandlePages[0].iheLimit = gpsi->cHandleEntries;
  597. /*
  598. * Initialize the handle entries.
  599. */
  600. HMInitHandleEntries(0);
  601. /*
  602. * PW(NULL) (ie, handle 0) must map to a NULL pointer.
  603. */
  604. gSharedInfo.aheList[0].phead = NULL;
  605. UserAssert(gSharedInfo.aheList[0].bType == TYPE_FREE);
  606. UserAssert(gSharedInfo.aheList[0].wUniq == 1);
  607. #if DBG
  608. /*
  609. * Make sure we don't need to add the special case to handle HMINDEXBITS
  610. * in this function.
  611. */
  612. UserAssert(gpsi->cHandleEntries <= HMINDEXBITS);
  613. /*
  614. * PDESKOBJHEAD won't do the right casting unless these structs have the
  615. * same size.
  616. */
  617. UserAssert(sizeof(THROBJHEAD) == sizeof(PROCOBJHEAD));
  618. UserAssert(sizeof(THRDESKHEAD) == sizeof(PROCDESKHEAD));
  619. UserAssert(sizeof(THRDESKHEAD) == sizeof(DESKOBJHEAD));
  620. /*
  621. * Validate type flags to make sure that assumptions made throughout HM
  622. * code are OK.
  623. */
  624. {
  625. PHANDLETYPEINFO pahti = (PHANDLETYPEINFO)gahti;
  626. UINT uTypes = TYPE_CTYPES;
  627. BYTE bObjectCreateFlags;
  628. while (uTypes-- != 0) {
  629. bObjectCreateFlags = pahti->bObjectCreateFlags;
  630. /*
  631. * Illegal flag combinations.
  632. */
  633. UserAssert(!((bObjectCreateFlags & OCF_DESKTOPHEAP) && (bObjectCreateFlags & OCF_MARKPROCESS)));
  634. /*
  635. * Pointless (and probably illegal) flag combinations.
  636. */
  637. UserAssert(!((bObjectCreateFlags & OCF_DESKTOPHEAP) && (bObjectCreateFlags & OCF_SHAREDHEAP)));
  638. UserAssert(!((bObjectCreateFlags & OCF_USEPOOLQUOTA) && (bObjectCreateFlags & OCF_SHAREDHEAP)));
  639. UserAssert(!((bObjectCreateFlags & OCF_THREADOWNED) && (bObjectCreateFlags & OCF_PROCESSOWNED)));
  640. UserAssert(!(bObjectCreateFlags & OCF_USEPOOLQUOTA)
  641. || !(bObjectCreateFlags & OCF_DESKTOPHEAP)
  642. || (bObjectCreateFlags & OCF_USEPOOLIFNODESKTOP));
  643. /*
  644. * Required flag combinations.
  645. */
  646. UserAssert(!(bObjectCreateFlags & OCF_DESKTOPHEAP)
  647. || (bObjectCreateFlags & (OCF_PROCESSOWNED | OCF_THREADOWNED)));
  648. UserAssert(!(bObjectCreateFlags & OCF_MARKPROCESS)
  649. || (bObjectCreateFlags & OCF_PROCESSOWNED));
  650. UserAssert(!(bObjectCreateFlags & OCF_USEPOOLIFNODESKTOP)
  651. || (bObjectCreateFlags & OCF_DESKTOPHEAP));
  652. pahti++;
  653. }
  654. }
  655. #endif
  656. return TRUE;
  657. }
  658. /***************************************************************************\
  659. * HMGrowHandleTable
  660. *
  661. * Grows the handle table. Assumes the handle table already exists.
  662. *
  663. * 01-13-92 ScottLu Created.
  664. \***************************************************************************/
  665. BOOL HMGrowHandleTable(
  666. VOID)
  667. {
  668. ULONG_PTR i, iheFirstFree;
  669. PHE pheT;
  670. PVOID p;
  671. PHANDLEPAGE phpNew;
  672. DWORD dwCommitOffset;
  673. SIZE_T ulCommit;
  674. NTSTATUS Status;
  675. /*
  676. * If we've run out of handle space, fail.
  677. */
  678. i = gpsi->cHandleEntries;
  679. if (i & ~HMINDEXBITS) {
  680. return FALSE;
  681. }
  682. /*
  683. * Grow the page table if need be.
  684. */
  685. i = gcHandlePages + 1;
  686. if (i > CPAGEENTRIESINIT) {
  687. DWORD dwSize = gcHandlePages * sizeof(HANDLEPAGE);
  688. phpNew = UserReAllocPool(gpHandlePages,
  689. dwSize,
  690. dwSize + sizeof(HANDLEPAGE),
  691. TAG_SYSTEM);
  692. if (phpNew == NULL) {
  693. return FALSE;
  694. }
  695. gpHandlePages = phpNew;
  696. }
  697. /*
  698. * Commit some more pages to the table. First find the
  699. * address where the commitment needs to be.
  700. */
  701. p = (PBYTE)gSharedInfo.aheList + gpsi->cbHandleTable;
  702. if (p >= Win32HeapGetHandle(gpvSharedAlloc)) {
  703. return FALSE;
  704. }
  705. dwCommitOffset = (ULONG)((PBYTE)p - (PBYTE)gpvSharedBase);
  706. ulCommit = PAGE_SIZE;
  707. Status = CommitReadOnlyMemory(ghSectionShared, &ulCommit, dwCommitOffset, NULL);
  708. if (!NT_SUCCESS(Status)) {
  709. return FALSE;
  710. }
  711. phpNew = &gpHandlePages[gcHandlePages++];
  712. /*
  713. * Update the global information to include the new
  714. * page.
  715. */
  716. iheFirstFree = gpsi->cHandleEntries;
  717. if (gpsi->cHandleEntries & 0x1) {
  718. phpNew->iheFreeOdd = gpsi->cHandleEntries;
  719. phpNew->iheFreeEven = gpsi->cHandleEntries + 1;
  720. } else {
  721. phpNew->iheFreeEven = gpsi->cHandleEntries;
  722. phpNew->iheFreeOdd = gpsi->cHandleEntries + 1;
  723. }
  724. gpsi->cbHandleTable += PAGE_SIZE;
  725. /*
  726. * Check for handle overflow.
  727. */
  728. gpsi->cHandleEntries = gpsi->cbHandleTable / sizeof(HANDLEENTRY);
  729. if (gpsi->cHandleEntries & ~HMINDEXBITS) {
  730. gpsi->cHandleEntries = (HMINDEXBITS + 1);
  731. }
  732. phpNew->iheLimit = gpsi->cHandleEntries;
  733. if (phpNew->iheFreeEven >= phpNew->iheLimit) {
  734. phpNew->iheFreeEven = 0;
  735. }
  736. if (phpNew->iheFreeOdd >= phpNew->iheLimit) {
  737. phpNew->iheFreeOdd = 0;
  738. }
  739. HMInitHandleEntries(iheFirstFree);
  740. /*
  741. * HMINDEXBITS has a special meaning. We used to handle this in HMAllocObject.
  742. * Now we handle it here right after adding that handle to the table.
  743. * Old Comment:
  744. * Reserve this table entry so that PW(HMINDEXBITS) maps to a
  745. * NULL pointer. Set it to TYPE_FREE so the cleanup code doesn't think
  746. * it is allocated. Set wUniq to 1 so that RevalidateHandles on HMINDEXBITS
  747. * will fail.
  748. */
  749. if ((gpsi->cHandleEntries > HMINDEXBITS)
  750. && (phpNew->iheFreeOdd != 0)
  751. && (phpNew->iheFreeOdd <= HMINDEXBITS)) {
  752. pheT = &gSharedInfo.aheList[HMINDEXBITS];
  753. if (phpNew->iheFreeOdd == HMINDEXBITS) {
  754. phpNew->iheFreeOdd = (ULONG_PTR)pheT->phead;
  755. } else {
  756. UserAssert(pheT - 2 >= &gSharedInfo.aheList[iheFirstFree]);
  757. UserAssert((pheT - 2)->phead == (PVOID)HMINDEXBITS);
  758. (pheT - 2)->phead = pheT->phead;
  759. }
  760. pheT->phead = NULL;
  761. UserAssert(pheT->bType == TYPE_FREE);
  762. UserAssert(pheT->wUniq == 1);
  763. }
  764. return TRUE;
  765. }
  766. /***************************************************************************\
  767. * HMAllocObject
  768. *
  769. * Allocs a non-secure object by allocating a handle and memory for
  770. * the object.
  771. *
  772. * 01-13-92 ScottLu Created.
  773. \***************************************************************************/
  774. PVOID HMAllocObject(
  775. PTHREADINFO ptiOwner,
  776. PDESKTOP pdeskSrc,
  777. BYTE bType,
  778. DWORD size)
  779. {
  780. DWORD i;
  781. PHEAD phead;
  782. PHE pheT;
  783. ULONG_PTR iheFree, *piheFreeHead;
  784. PHANDLEPAGE php;
  785. BYTE bCreateFlags;
  786. PPROCESSINFO ppiQuotaCharge = NULL;
  787. BOOL fUsePoolIfNoDesktop;
  788. BOOL fEven;
  789. #if DBG
  790. SIZE_T dwAllocSize;
  791. #endif
  792. CheckCritIn();
  793. bCreateFlags = gahti[bType].bObjectCreateFlags;
  794. #if DBG
  795. /*
  796. * Validate size
  797. */
  798. if (bCreateFlags & OCF_VARIABLESIZE) {
  799. UserAssert(gahti[bType].uSize <= size);
  800. } else {
  801. UserAssert(gahti[bType].uSize == size);
  802. }
  803. #endif
  804. /*
  805. * Check for process handle quota
  806. */
  807. if (bCreateFlags & (OCF_PROCESSOWNED | OCF_THREADOWNED)) {
  808. UserAssert(ptiOwner != NULL);
  809. ppiQuotaCharge = ptiOwner->ppi;
  810. if (ppiQuotaCharge->UserHandleCount >= gUserProcessHandleQuota) {
  811. RIPERR0(ERROR_NO_MORE_USER_HANDLES,
  812. RIP_WARNING,
  813. "USER: HMAllocObject: out of handle quota");
  814. return NULL;
  815. }
  816. }
  817. /*
  818. * Find the next free handle
  819. * Window handles must be even; hence we try first to use odd handles
  820. * for all other objects.
  821. * Old comment:
  822. * Some wow apps, like WinProj, require even Window handles so we'll
  823. * accomodate them; build a list of the odd handles so they won't get lost
  824. * 10/13/97: WinProj never fixed this; even the 32 bit version has the problem.
  825. */
  826. fEven = (bType == TYPE_WINDOW);
  827. piheFreeHead = NULL;
  828. do {
  829. php = gpHandlePages;
  830. for (i = 0; i < gcHandlePages; ++i, ++php) {
  831. if (fEven) {
  832. if (php->iheFreeEven != 0) {
  833. piheFreeHead = &php->iheFreeEven;
  834. break;
  835. }
  836. } else {
  837. if (php->iheFreeOdd != 0) {
  838. piheFreeHead = &php->iheFreeOdd;
  839. break;
  840. }
  841. }
  842. } /* for */
  843. /*
  844. * If we couldn't find an odd handle, then search for an even one
  845. */
  846. fEven = ((piheFreeHead == NULL) && !fEven);
  847. } while (fEven);
  848. /*
  849. * If there are no free handles we can use, grow the table
  850. */
  851. if (piheFreeHead == NULL) {
  852. HMGrowHandleTable();
  853. /*
  854. * If the table didn't grow, get out.
  855. */
  856. if (i == gcHandlePages) {
  857. RIPMSG0(RIP_WARNING, "HMAllocObject: could not grow handle space");
  858. return NULL;
  859. }
  860. /*
  861. * Because the handle page table may have moved,
  862. * recalc the page entry pointer.
  863. */
  864. php = &gpHandlePages[i];
  865. piheFreeHead = (bType == TYPE_WINDOW ? &php->iheFreeEven : &php->iheFreeOdd);
  866. if (*piheFreeHead == 0) {
  867. UserAssert(gpsi->cHandleEntries == (HMINDEXBITS + 1));
  868. RIPMSG0(RIP_WARNING, "HMAllocObject: handle table is full");
  869. return NULL;
  870. }
  871. }
  872. /*
  873. * HMINDEXBITS is a reserved value that should never be in the free lists
  874. * (see HMGrowHandleTable()).
  875. */
  876. UserAssert(HMIndexFromHandle(*piheFreeHead) != HMINDEXBITS);
  877. /*
  878. * Try to allocate the object. If this fails, bail out.
  879. */
  880. if ((bCreateFlags & OCF_DESKTOPHEAP) && pdeskSrc) {
  881. phead = (PHEAD)DesktopAlloc(pdeskSrc, size, MAKELONG(DTAG_HANDTABL, bType));
  882. if (phead) {
  883. LockDesktop(&((PDESKOBJHEAD)phead)->rpdesk, pdeskSrc, LDL_OBJ_DESK, (ULONG_PTR)phead);
  884. ((PDESKOBJHEAD)phead)->pSelf = (PBYTE)phead;
  885. #if DBG
  886. dwAllocSize = Win32HeapSize(pdeskSrc->pheapDesktop, phead);
  887. #endif
  888. }
  889. } else if (bCreateFlags & OCF_SHAREDHEAP) {
  890. UserAssert(!pdeskSrc);
  891. phead = (PHEAD)SharedAlloc(size);
  892. #if DBG
  893. if (phead) {
  894. dwAllocSize = Win32HeapSize(gpvSharedAlloc, phead);
  895. }
  896. #endif
  897. } else {
  898. fUsePoolIfNoDesktop = !pdeskSrc && (bCreateFlags & OCF_USEPOOLIFNODESKTOP);
  899. UserAssert(!(bCreateFlags & OCF_DESKTOPHEAP) || fUsePoolIfNoDesktop);
  900. if ((bCreateFlags & OCF_USEPOOLQUOTA) && !fUsePoolIfNoDesktop) {
  901. phead = (PHEAD)UserAllocPoolWithQuotaZInit(size, gahti[bType].dwAllocTag);
  902. } else {
  903. phead = (PHEAD)UserAllocPoolZInit(size, gahti[bType].dwAllocTag);
  904. }
  905. #if DBG
  906. if (phead) {
  907. dwAllocSize = Win32QueryPoolSize(phead);
  908. }
  909. #endif
  910. }
  911. if (phead == NULL) {
  912. RIPERR0(ERROR_NOT_ENOUGH_MEMORY,
  913. RIP_WARNING,
  914. "USER: HMAllocObject: out of memory");
  915. return NULL;
  916. }
  917. /*
  918. * We're going to use this handle so get it off its free list.
  919. * The free handle phead points to the next free handle.
  920. */
  921. iheFree = *piheFreeHead;
  922. pheT = &gSharedInfo.aheList[iheFree];
  923. *piheFreeHead = (ULONG_PTR)pheT->phead;
  924. DBGHMValidateFreeLists();
  925. /*
  926. * Track high water mark for handle allocation.
  927. */
  928. if ((DWORD)iheFree > giheLast) {
  929. giheLast = (DWORD)iheFree;
  930. }
  931. /*
  932. * Setup the handle contents, plus initialize the object header.
  933. */
  934. pheT->bType = bType;
  935. pheT->phead = phead;
  936. UserAssert(pheT->bFlags == 0);
  937. if (bCreateFlags & OCF_PROCESSOWNED) {
  938. if ((ptiOwner->TIF_flags & TIF_16BIT) && (ptiOwner->ptdb)) {
  939. ((PPROCOBJHEAD)phead)->hTaskWow = ptiOwner->ptdb->hTaskWow;
  940. } else {
  941. ((PPROCOBJHEAD)phead)->hTaskWow = 0;
  942. }
  943. pheT->pOwner = ptiOwner->ppi;
  944. if (bCreateFlags & OCF_MARKPROCESS) {
  945. ((PPROCMARKHEAD)phead)->ppi = ptiOwner->ppi;
  946. }
  947. } else if (bCreateFlags & OCF_THREADOWNED) {
  948. ((PTHROBJHEAD)phead)->pti = pheT->pOwner = ptiOwner;
  949. } else {
  950. /*
  951. * The caller is wasting time if ptiOwner != NULL
  952. * The handle entry must already have pOwner == NULL.
  953. */
  954. UserAssert(ptiOwner == NULL);
  955. UserAssert(pheT->pOwner == NULL);
  956. }
  957. phead->h = HMHandleFromIndex(iheFree);
  958. if (ppiQuotaCharge) {
  959. ppiQuotaCharge->UserHandleCount++;
  960. DBGValidateHandleQuota();
  961. }
  962. #if DBG
  963. /*
  964. * Performance counters.
  965. */
  966. gaPerfhti[bType].lTotalCount++;
  967. gaPerfhti[bType].lCount++;
  968. if (gaPerfhti[bType].lCount > gaPerfhti[bType].lMaxCount) {
  969. gaPerfhti[bType].lMaxCount = gaPerfhti[bType].lCount;
  970. }
  971. gaPerfhti[bType].lSize += dwAllocSize;
  972. #endif // DBG
  973. /*
  974. * Return a handle entry pointer.
  975. */
  976. return pheT->phead;
  977. }
  978. /***************************************************************************\
  979. * HMFreeObject
  980. *
  981. * Frees an object - the handle and the referenced memory.
  982. *
  983. * 01-13-92 ScottLu Created.
  984. \***************************************************************************/
  985. BOOL HMFreeObject(
  986. PVOID pobj)
  987. {
  988. PHE pheT;
  989. WORD wUniqT;
  990. PHANDLEPAGE php;
  991. DWORD i;
  992. ULONG_PTR iheCurrent, *piheCurrentHead;
  993. BYTE bCreateFlags;
  994. PDESKTOP pdesk;
  995. PPROCESSINFO ppiQuotaCharge = NULL;
  996. #if DBG || FRE_LOCK_RECORD
  997. PLR plrT, plrNextT;
  998. #endif
  999. UserAssert(((PHEAD)pobj)->cLockObj == 0);
  1000. UserAssert(pobj == HtoPqCat(PtoHq(pobj)));
  1001. /*
  1002. * Free the object first.
  1003. */
  1004. pheT = HMPheFromObject(pobj);
  1005. bCreateFlags = gahti[pheT->bType].bObjectCreateFlags;
  1006. UserAssertMsg1(pheT->bType != TYPE_FREE,
  1007. "Object already marked as freed! %#p", pobj);
  1008. /*
  1009. * Adjust the process handle usage.
  1010. */
  1011. if (bCreateFlags & OCF_PROCESSOWNED) {
  1012. ppiQuotaCharge = (PPROCESSINFO)pheT->pOwner;
  1013. UserAssert(ppiQuotaCharge != NULL);
  1014. } else if (bCreateFlags & OCF_THREADOWNED) {
  1015. ppiQuotaCharge = (PPROCESSINFO)(((PTHREADINFO)(pheT->pOwner))->ppi);
  1016. UserAssert(ppiQuotaCharge != NULL);
  1017. } else {
  1018. ppiQuotaCharge = NULL;
  1019. }
  1020. if (ppiQuotaCharge != NULL) {
  1021. ppiQuotaCharge->UserHandleCount--;
  1022. }
  1023. if (pheT->bFlags & HANDLEF_GRANTED) {
  1024. HMCleanupGrantedHandle(pheT->phead->h);
  1025. pheT->bFlags &= ~HANDLEF_GRANTED;
  1026. }
  1027. #if DBG
  1028. /*
  1029. * Performance counters.
  1030. */
  1031. gaPerfhti[pheT->bType].lCount--;
  1032. if ((pheT->bFlags & HANDLEF_POOL) == 0 && (bCreateFlags & OCF_DESKTOPHEAP) && ((PDESKOBJHEAD)pobj)->rpdesk) {
  1033. pdesk = ((PDESKOBJHEAD)pobj)->rpdesk;
  1034. gaPerfhti[pheT->bType].lSize -= Win32HeapSize(pdesk->pheapDesktop, pobj);
  1035. } else if ((pheT->bFlags & HANDLEF_POOL) == 0 && bCreateFlags & OCF_SHAREDHEAP) {
  1036. gaPerfhti[pheT->bType].lSize -= Win32HeapSize(gpvSharedAlloc, pobj);
  1037. } else {
  1038. gaPerfhti[pheT->bType].lSize -= Win32QueryPoolSize(pobj);
  1039. }
  1040. #endif // DBG
  1041. if ((bCreateFlags & OCF_DESKTOPHEAP)) {
  1042. #if DBG
  1043. BOOL bSuccess;
  1044. #endif
  1045. if (!(pheT->bFlags & HANDLEF_POOL)) {
  1046. UserAssert(((PDESKOBJHEAD)pobj)->rpdesk != NULL);
  1047. }
  1048. /*
  1049. * pobj->rpdesk is cached and the object is freed after which the
  1050. * reference count on the desktop is decremented. This is done in
  1051. * this order such that if this is the last reference on the desktop
  1052. * the desktop heap is not destroyed before we free the object.
  1053. */
  1054. pdesk = ((PDESKOBJHEAD)pobj)->rpdesk;
  1055. ((PDESKOBJHEAD)pobj)->rpdesk = NULL;
  1056. if (pheT->bFlags & HANDLEF_POOL) {
  1057. UserFreePool(pobj);
  1058. } else {
  1059. #if DBG
  1060. bSuccess =
  1061. #endif
  1062. DesktopFree(pdesk, pobj);
  1063. #if DBG
  1064. if (!bSuccess) {
  1065. /*
  1066. * We would hit this assert in HYDRA trying to free the
  1067. * mother desktop window which was allocated out of pool
  1068. */
  1069. RIPMSG1(RIP_ERROR, "Object already freed from desktop heap! %#p", pobj);
  1070. }
  1071. #endif
  1072. }
  1073. /*
  1074. * NOTE: Using pobj after freeing the object is not a problem because
  1075. * UnlockDesktop uses the value for tracking and doesn't dereference
  1076. * the pointer. If this ever changes we'll get a BC.
  1077. */
  1078. UnlockDesktop(&pdesk, LDU_OBJ_DESK, (ULONG_PTR)pobj);
  1079. } else if (bCreateFlags & OCF_SHAREDHEAP) {
  1080. SharedFree(pobj);
  1081. } else {
  1082. UserFreePool(pobj);
  1083. }
  1084. #if DBG || FRE_LOCK_RECORD
  1085. /*
  1086. * Go through and delete the lock records, if they exist.
  1087. */
  1088. for (plrT = pheT->plr; plrT != NULL; plrT = plrNextT) {
  1089. /*
  1090. * Remember the next one before freeing this one.
  1091. */
  1092. plrNextT = plrT->plrNext;
  1093. FreeLockRecord((HANDLE)plrT);
  1094. }
  1095. #endif
  1096. /*
  1097. * Clear the handle contents. Need to remember the uniqueness across
  1098. * the clear. Also, advance uniqueness on free so that uniqueness checking
  1099. * against old handles also fails.
  1100. */
  1101. wUniqT = (WORD)((pheT->wUniq + 1) & HMUNIQBITS);
  1102. /*
  1103. * Be sure that wUniqT will never be 0 nor HMUNIQBITS.
  1104. * Then if we hit the max (i.e. HMUNIQBITS) then reset it to 1.
  1105. */
  1106. if (wUniqT == HMUNIQBITS) {
  1107. wUniqT = 1;
  1108. }
  1109. RtlZeroMemory(pheT, sizeof(HANDLEENTRY));
  1110. pheT->wUniq = wUniqT;
  1111. UserAssert(pheT->bType == TYPE_FREE);
  1112. /*
  1113. * Put the handle on the free list of the appropriate page.
  1114. */
  1115. php = gpHandlePages;
  1116. iheCurrent = pheT - gSharedInfo.aheList;
  1117. for (i = 0; i < gcHandlePages; ++i, ++php) {
  1118. if (iheCurrent < php->iheLimit) {
  1119. piheCurrentHead = (iheCurrent & 0x1 ? &php->iheFreeOdd : &php->iheFreeEven);
  1120. pheT->phead = (PHEAD)*piheCurrentHead;
  1121. *piheCurrentHead = iheCurrent;
  1122. DBGHMValidateFreeLists();
  1123. break;
  1124. }
  1125. }
  1126. /*
  1127. * We must have found it.
  1128. */
  1129. UserAssert(i < gcHandlePages);
  1130. UserAssert(pheT->pOwner == NULL);
  1131. DBGValidateHandleQuota();
  1132. return TRUE;
  1133. }
  1134. /***************************************************************************\
  1135. * HMMarkObjectDestroy
  1136. *
  1137. * Marks an object for destruction.
  1138. *
  1139. * Returns TRUE if the object can be destroyed; that is, if it's
  1140. * lock count is 0.
  1141. *
  1142. * 02-10-92 ScottLu Created.
  1143. \***************************************************************************/
  1144. BOOL HMMarkObjectDestroy(
  1145. PVOID pobj)
  1146. {
  1147. PHE phe = HMPheFromObject(pobj);
  1148. #if DBG || FRE_LOCK_RECORD
  1149. /*
  1150. * Record where the object was marked for destruction.
  1151. */
  1152. if (RecordLockThisType(pobj)) {
  1153. if (!(phe->bFlags & HANDLEF_DESTROY)) {
  1154. HMRecordLock(LOCKRECORD_MARKDESTROY, pobj, ((PHEAD)pobj)->cLockObj);
  1155. }
  1156. }
  1157. #endif
  1158. /*
  1159. * Set the destroy flag so our unlock code will know we're trying to
  1160. * destroy this object.
  1161. */
  1162. phe->bFlags |= HANDLEF_DESTROY;
  1163. /*
  1164. * If this object can't be destroyed, then CLEAR the HANDLEF_INDESTROY
  1165. * flag - because this object won't be currently "in destruction"!
  1166. * (if we didn't clear it, when it was unlocked it wouldn't get destroyed).
  1167. */
  1168. if (((PHEAD)pobj)->cLockObj != 0) {
  1169. phe->bFlags &= ~HANDLEF_INDESTROY;
  1170. /*
  1171. * Return FALSE because we can't destroy this object.
  1172. */
  1173. return FALSE;
  1174. }
  1175. #if DBG
  1176. /*
  1177. * Ensure that this function only returns TRUE once.
  1178. */
  1179. UserAssert(!(phe->bFlags & HANDLEF_MARKED_OK));
  1180. phe->bFlags |= HANDLEF_MARKED_OK;
  1181. #endif
  1182. /*
  1183. * Return TRUE because Lock count is zero - ok to destroy this object.
  1184. */
  1185. return TRUE;
  1186. }
  1187. /***************************************************************************\
  1188. * HMDestroyObject
  1189. *
  1190. * This routine marks an object for destruction, and frees it if
  1191. * it is unlocked.
  1192. *
  1193. * 10-13-94 JimA Created.
  1194. \***************************************************************************/
  1195. BOOL HMDestroyObject(
  1196. PVOID pobj)
  1197. {
  1198. /*
  1199. * First mark the object for destruction. This tells the locking code
  1200. * that we want to destroy this object when the lock count goes to 0.
  1201. * If this returns FALSE, we can't destroy the object yet (and can't get
  1202. * rid of security yet either.)
  1203. */
  1204. if (!HMMarkObjectDestroy(pobj))
  1205. return FALSE;
  1206. /*
  1207. * Ok to destroy... Free the handle (which will free the object
  1208. * and the handle).
  1209. */
  1210. HMFreeObject(pobj);
  1211. return TRUE;
  1212. }
  1213. #if DBG || FRE_LOCK_RECORD
  1214. NTSTATUS
  1215. InitLockRecordLookaside()
  1216. {
  1217. LockRecordLookaside = Win32AllocPoolNonPagedNS(sizeof(PAGED_LOOKASIDE_LIST),
  1218. TAG_LOOKASIDE);
  1219. if (LockRecordLookaside == NULL) {
  1220. return STATUS_NO_MEMORY;
  1221. }
  1222. ExInitializePagedLookasideList(LockRecordLookaside,
  1223. NULL,
  1224. NULL,
  1225. SESSION_POOL_MASK,
  1226. sizeof(LOCKRECORD),
  1227. TAG_LOCKRECORD,
  1228. 1000);
  1229. return STATUS_SUCCESS;
  1230. }
  1231. PLR AllocLockRecord()
  1232. {
  1233. PLR plr;
  1234. /*
  1235. * Allocate a LOCKRECORD structure.
  1236. */
  1237. if ((plr = ExAllocateFromPagedLookasideList(LockRecordLookaside)) == NULL) {
  1238. return NULL;
  1239. }
  1240. RtlZeroMemory(plr, sizeof(*plr));
  1241. return plr;
  1242. }
  1243. VOID FreeLockRecord(
  1244. PLR plr)
  1245. {
  1246. ExFreeToPagedLookasideList(LockRecordLookaside, plr);
  1247. }
  1248. /***************************************************************************\
  1249. * HMRecordLock
  1250. *
  1251. * This routine records a lock on a "lock list", so that locks and unlocks
  1252. * can be tracked in the debugger. Only called if DBGTAG_TrackLocks is enabled.
  1253. *
  1254. * 02-27-92 ScottLu Created.
  1255. \***************************************************************************/
  1256. VOID HMRecordLock(
  1257. PVOID ppobj,
  1258. PVOID pobj,
  1259. DWORD cLockObj)
  1260. {
  1261. PHE phe;
  1262. PLR plr;
  1263. int i;
  1264. phe = HMPheFromObject(pobj);
  1265. if ((plr = AllocLockRecord()) == NULL) {
  1266. RIPMSG0(RIP_WARNING, "HMRecordLock failed to allocate memory");
  1267. return;
  1268. }
  1269. /*
  1270. * Link it in front of the list
  1271. */
  1272. plr->plrNext = phe->plr;
  1273. phe->plr = plr;
  1274. /*
  1275. * This propably happens only for unmatched locks
  1276. */
  1277. if (((PHEAD)pobj)->cLockObj > cLockObj) {
  1278. RIPMSG3(RIP_WARNING, "Unmatched lock. ppobj %#p pobj %#p cLockObj %d",
  1279. ppobj, pobj, cLockObj);
  1280. i = (int)cLockObj;
  1281. i = -i;
  1282. cLockObj = (DWORD)i;
  1283. }
  1284. plr->ppobj = ppobj;
  1285. plr->cLockObj = cLockObj;
  1286. RtlWalkFrameChain(plr->trace, LOCKRECORD_STACK, 0);
  1287. }
  1288. #endif
  1289. #if DBG
  1290. /***************************************************************************\
  1291. * HMLockObject
  1292. *
  1293. * This routine locks an object. This is a macro in retail systems.
  1294. *
  1295. * 02-24-92 ScottLu Created.
  1296. \***************************************************************************/
  1297. VOID HMLockObject(
  1298. PVOID pobj)
  1299. {
  1300. HANDLE h;
  1301. PVOID pobjValidate;
  1302. /*
  1303. * Validate by going through the handle entry so that we make sure pobj
  1304. * is not just pointing off into space. This may GP fault, but that's
  1305. * ok: this case should not ever happen if we're bug free.
  1306. */
  1307. h = HMPheFromObject(pobj)->phead->h;
  1308. pobjValidate = HMRevalidateCatHandle(h);
  1309. if (!pobj || pobj != pobjValidate) {
  1310. RIPMSG2(RIP_ERROR,
  1311. "HMLockObject invalid object %#p, handle %#p",
  1312. pobj, h);
  1313. return;
  1314. }
  1315. /*
  1316. * Inc the reference count.
  1317. */
  1318. ((PHEAD)pobj)->cLockObj++;
  1319. if (((PHEAD)pobj)->cLockObj == 0) {
  1320. RIPMSG1(RIP_ERROR, "Object lock count has overflowed: %#p", pobj);
  1321. }
  1322. }
  1323. #endif // DBG
  1324. /***************************************************************************\
  1325. * HMUnlockObjectInternal
  1326. *
  1327. * This routine is called from the macro HMUnlockObject when an object's
  1328. * reference count drops to zero. This routine will destroy an object
  1329. * if is has been marked for destruction.
  1330. *
  1331. * 01-21-92 ScottLu Created.
  1332. \***************************************************************************/
  1333. PVOID HMUnlockObjectInternal(
  1334. PVOID pobj)
  1335. {
  1336. PHE phe;
  1337. /*
  1338. * The object is not reference counted. If the object is not a zombie,
  1339. * return success because the object is still around.
  1340. */
  1341. phe = HMPheFromObject(pobj);
  1342. if (!(phe->bFlags & HANDLEF_DESTROY))
  1343. return pobj;
  1344. /*
  1345. * We're destroying the object based on an unlock... Make sure it isn't
  1346. * currently being destroyed! (It is valid to have lock counts go from
  1347. * 0 to != 0 to 0 during destruction... don't want recursion into
  1348. * the destroy routine.
  1349. */
  1350. if (phe->bFlags & HANDLEF_INDESTROY)
  1351. return pobj;
  1352. HMDestroyUnlockedObject(phe);
  1353. return NULL;
  1354. }
  1355. /***************************************************************************\
  1356. * HMAssignmentLock
  1357. *
  1358. * This api is used for structure and global variable assignment.
  1359. * Returns pobjOld if the object was *not* destroyed. Means the object is
  1360. * still valid.
  1361. *
  1362. * 02-24-92 ScottLu Created.
  1363. \***************************************************************************/
  1364. PVOID FASTCALL HMAssignmentLock(
  1365. PVOID *ppobj,
  1366. PVOID pobj)
  1367. {
  1368. PVOID pobjOld;
  1369. pobjOld = *ppobj;
  1370. *ppobj = pobj;
  1371. /*
  1372. * Unlocks the old, locks the new.
  1373. */
  1374. if (pobjOld != NULL) {
  1375. /*
  1376. * if we are locking in the same object that is there then
  1377. * it is a no-op but we don't want to do the Unlock and the Lock
  1378. * because the unlock could free object and the lock would lock
  1379. * in a freed pointer; 6410.
  1380. */
  1381. if (pobjOld == pobj) {
  1382. return pobjOld;
  1383. }
  1384. #if DBG || FRE_LOCK_RECORD
  1385. /*
  1386. * Track assignment locks.
  1387. */
  1388. if (RecordLockThisType(pobjOld)) {
  1389. if (!HMUnrecordLock(ppobj, pobjOld)) {
  1390. HMRecordLock(ppobj, pobjOld, ((PHEAD)pobjOld)->cLockObj - 1);
  1391. }
  1392. }
  1393. #endif
  1394. }
  1395. if (pobj != NULL) {
  1396. UserAssert(pobj == HMValidateCatHandleNoSecure(((PHEAD)pobj)->h, TYPE_GENERIC));
  1397. if (HMIsMarkDestroy(pobj)) {
  1398. RIPERR2(ERROR_INVALID_PARAMETER,
  1399. RIP_WARNING,
  1400. "HMAssignmentLock, locking object %#p marked for destruction at %#p",
  1401. pobj, ppobj);
  1402. }
  1403. #if DBG || FRE_LOCK_RECORD
  1404. /*
  1405. * Track assignment locks.
  1406. */
  1407. if (RecordLockThisType(pobj)) {
  1408. HMRecordLock(ppobj, pobj, ((PHEAD)pobj)->cLockObj + 1);
  1409. if (HMIsMarkDestroy(pobj)) {
  1410. RIPMSG2(RIP_WARNING,
  1411. "Locking object %#p marked for destruction at %#p",
  1412. pobj, ppobj);
  1413. }
  1414. }
  1415. #endif
  1416. HMLockObject(pobj);
  1417. }
  1418. /*
  1419. * This unlock has been moved from up above, so that we implement a
  1420. * "lock before unlock" strategy. Just in case pobjOld was the
  1421. * only object referencing pobj, pobj won't go away when we unlock
  1422. * pobjNew -- it will have been locked above.
  1423. */
  1424. if (pobjOld) {
  1425. pobjOld = HMUnlockObject(pobjOld);
  1426. }
  1427. return pobjOld;
  1428. }
  1429. /***************************************************************************\
  1430. * HMAssignmentUnLock
  1431. *
  1432. * This api is used for structure and global variable assignment.
  1433. * Returns pobjOld if the object was *not* destroyed. Means the object is
  1434. * still valid.
  1435. *
  1436. * 02-24-92 ScottLu Created.
  1437. \***************************************************************************/
  1438. PVOID FASTCALL HMAssignmentUnlock(
  1439. PVOID *ppobj)
  1440. {
  1441. PVOID pobjOld;
  1442. pobjOld = *ppobj;
  1443. *ppobj = NULL;
  1444. /*
  1445. * Unlocks the old, locks the new.
  1446. */
  1447. if (pobjOld != NULL) {
  1448. #if DBG || FRE_LOCK_RECORD
  1449. /*
  1450. * Track assignment locks.
  1451. */
  1452. if (RecordLockThisType(pobjOld)) {
  1453. if (!HMUnrecordLock(ppobj, pobjOld)) {
  1454. HMRecordLock(ppobj, pobjOld, ((PHEAD)pobjOld)->cLockObj - 1);
  1455. }
  1456. }
  1457. #endif
  1458. pobjOld = HMUnlockObject(pobjOld);
  1459. }
  1460. return pobjOld;
  1461. }
  1462. /***************************************************************************\
  1463. * IsValidThreadLock
  1464. *
  1465. * This routine checks to make sure that the thread lock structures passed
  1466. * in are valid.
  1467. *
  1468. * 03-17-92 ScottLu Created.
  1469. * 02-22-99 MCostea Also validate the shadow of the stack TL
  1470. * from gThreadLocksArray
  1471. \***************************************************************************/
  1472. #if DBG
  1473. VOID IsValidThreadLock(
  1474. PTHREADINFO pti,
  1475. PTL ptl,
  1476. ULONG_PTR dwLimit,
  1477. BOOLEAN fHM)
  1478. {
  1479. /*
  1480. * Check that ptl is a valid stack address. Allow ptl == dwLimit so we
  1481. * can call ValidateThreadLocks passing the address of the last thing we
  1482. * locked.
  1483. */
  1484. UserAssert((ULONG_PTR)ptl >= dwLimit);
  1485. UserAssert((ULONG_PTR)ptl < (ULONG_PTR)PsGetCurrentThreadStackBase());
  1486. /*
  1487. * Check ptl owner.
  1488. */
  1489. UserAssert(ptl->pW32Thread == (PW32THREAD)pti);
  1490. /*
  1491. * If this is an HM object, verify handle and lock count (guess max value)
  1492. */
  1493. if (fHM && (ptl->pobj != NULL)) {
  1494. /*
  1495. * The locked object could be a destroyed object.
  1496. */
  1497. UserAssert(ptl->pobj == HtoPqCat(PtoHq(ptl->pobj)));
  1498. if (((PHEAD)ptl->pobj)->cLockObj >= 32000) {
  1499. RIPMSG2(RIP_WARNING,
  1500. "IsValidThreadLock: Object %#p has %d locks",
  1501. ptl->pobj,
  1502. ((PHEAD)ptl->pobj)->cLockObj);
  1503. }
  1504. }
  1505. /*
  1506. * Make sure the shadow in gThreadLocksArray is doing fine.
  1507. */
  1508. UserAssert(ptl->ptl->ptl == ptl);
  1509. }
  1510. #endif
  1511. #if DBG
  1512. /***************************************************************************\
  1513. * ValidateThreadLocks
  1514. *
  1515. * This routine validates the thread lock list of a thread.
  1516. *
  1517. * 03-10-92 ScottLu Created.
  1518. \***************************************************************************/
  1519. ULONG ValidateThreadLocks(
  1520. PTL NewLock,
  1521. PTL OldLock,
  1522. ULONG_PTR dwLimit,
  1523. BOOLEAN fHM)
  1524. {
  1525. UINT uTLCount = 0;
  1526. PTL ptlTopLock = OldLock;
  1527. PTHREADINFO ptiCurrent;
  1528. BEGIN_REENTERCRIT();
  1529. ptiCurrent = PtiCurrent();
  1530. /*
  1531. * Validate the new thread lock.
  1532. */
  1533. if (NewLock != NULL) {
  1534. UserAssert(NewLock->next == OldLock);
  1535. IsValidThreadLock(ptiCurrent, NewLock, dwLimit, fHM);
  1536. uTLCount++;
  1537. }
  1538. /*
  1539. * Loop through the list of thread locks and check to make sure the
  1540. * new lock is not in the list and that list is valid.
  1541. */
  1542. while (OldLock != NULL) {
  1543. /*
  1544. * The new lock must not be the same as the old lock.
  1545. */
  1546. UserAssert(NewLock != OldLock);
  1547. /*
  1548. * Validate the old thread lock.
  1549. */
  1550. IsValidThreadLock(ptiCurrent, OldLock, dwLimit, fHM);
  1551. uTLCount++;
  1552. OldLock = OldLock->next;
  1553. }
  1554. /*
  1555. * If this is thread lock, set uTLCount, else verify it
  1556. */
  1557. if (NewLock != NULL) {
  1558. NewLock->uTLCount = uTLCount;
  1559. } else {
  1560. if (ptlTopLock == NULL) {
  1561. RIPMSG0(RIP_WARNING, "ptlTopLock is NULL, the system will AV now");
  1562. }
  1563. UserAssert(uTLCount == ptlTopLock->uTLCount);
  1564. }
  1565. END_REENTERCRIT();
  1566. return uTLCount;
  1567. }
  1568. #endif // DBG
  1569. #if DBG
  1570. /***************************************************************************\
  1571. * CreateShadowTL
  1572. *
  1573. * This function creates a shaddow for the stack allocated ptl parameter
  1574. * in the global thread locks arrays
  1575. *
  1576. * 08-04-99 MCostea Created.
  1577. \***************************************************************************/
  1578. VOID CreateShadowTL(
  1579. PTL ptl)
  1580. {
  1581. PTL pTLNextFree;
  1582. if (gFreeTLList->next == NULL) {
  1583. UserAssert(gcThreadLocksArraysAllocated < MAX_THREAD_LOCKS_ARRAYS &&
  1584. "No more room in gpaThreadLocksArrays! The system will bugcheck.");
  1585. gFreeTLList->next = gpaThreadLocksArrays[gcThreadLocksArraysAllocated] =
  1586. UserAllocPoolZInit(sizeof(TL)*MAX_THREAD_LOCKS, TAG_GLOBALTHREADLOCK);
  1587. if (gFreeTLList->next == NULL) {
  1588. UserAssert("Can't allocate memory for gpaThreadLocksArrays: the system will bugcheck soon!");
  1589. }
  1590. InitGlobalThreadLockArray(gcThreadLocksArraysAllocated);
  1591. gcThreadLocksArraysAllocated++;
  1592. }
  1593. pTLNextFree = gFreeTLList->next;
  1594. RtlCopyMemory(gFreeTLList, ptl, sizeof(TL));
  1595. gFreeTLList->ptl = ptl;
  1596. ptl->ptl = gFreeTLList;
  1597. gFreeTLList = pTLNextFree;
  1598. }
  1599. #endif // DBG
  1600. /***************************************************************************\
  1601. * ThreadLock
  1602. *
  1603. * This api is used for locking objects across callbacks, so they are still
  1604. * there when the callback returns.
  1605. *
  1606. * 03-04-92 ScottLu Created.
  1607. \***************************************************************************/
  1608. #if DBG
  1609. VOID
  1610. ThreadLock(
  1611. PVOID pobj,
  1612. PTL ptl)
  1613. {
  1614. PTHREADINFO ptiCurrent;
  1615. PVOID pfnT;
  1616. /*
  1617. * This is a handy place, because it is called so often, to see if we're
  1618. * eating up too much stack.
  1619. */
  1620. ASSERT_STACK();
  1621. /*
  1622. * Store the address of the object in the thread lock structure and
  1623. * link the structure into the thread lock list.
  1624. *
  1625. * N.B. The lock structure is always linked into the thread lock list
  1626. * regardless of whether the object address is NULL. The reason
  1627. * this is done is so the lock address does not need to be passed
  1628. * to the unlock function since the first entry in the lock list
  1629. * is always the entry to be unlocked.
  1630. */
  1631. UserAssert(!(PpiCurrent()->W32PF_Flags & W32PF_TERMINATED));
  1632. ptiCurrent = PtiCurrent();
  1633. UserAssert(ptiCurrent);
  1634. /*
  1635. * Get the callers address and validate the thread lock list.
  1636. */
  1637. RtlGetCallersAddress(&ptl->pfnCaller, &pfnT);
  1638. ptl->pW32Thread = (PW32THREAD)ptiCurrent;
  1639. ptl->next = ptiCurrent->ptl;
  1640. ptiCurrent->ptl = ptl;
  1641. ptl->pobj = pobj;
  1642. if (pobj != NULL) {
  1643. HMLockObject(pobj);
  1644. }
  1645. CreateShadowTL(ptl);
  1646. ValidateThreadLocks(ptl, ptl->next, (ULONG_PTR)&pobj, TRUE);
  1647. }
  1648. #endif
  1649. /***************************************************************************\
  1650. * ThreadLockExchange
  1651. *
  1652. * Reuses a TL structure by locking the new object and unlocking
  1653. * the old one. This is used where you enumerate a list of
  1654. * structure locked objects, e.g. the window list.
  1655. *
  1656. * History:
  1657. * 05-Mar-1997 adams Created.
  1658. \***************************************************************************/
  1659. #if DBG
  1660. PVOID
  1661. ThreadLockExchange(PVOID pobj, PTL ptl)
  1662. {
  1663. PTHREADINFO ptiCurrent;
  1664. PVOID pobjOld;
  1665. PVOID pfnT;
  1666. /*
  1667. * This is a handy place, because it is called so often, to see if User is
  1668. * eating up too much stack.
  1669. */
  1670. ASSERT_STACK();
  1671. /*
  1672. * Store the address of the object in the thread lock structure and
  1673. * link the structure into the thread lock list.
  1674. *
  1675. * N.B. The lock structure is always linked into the thread lock list
  1676. * regardless of whether the object address is NULL. The reason
  1677. * this is done is so the lock address does not need to be passed
  1678. * to the unlock function since the first entry in the lock list
  1679. * is always the entry to be unlocked.
  1680. */
  1681. UserAssert(!(PpiCurrent()->W32PF_Flags & W32PF_TERMINATED));
  1682. ptiCurrent = PtiCurrent();
  1683. UserAssert(ptiCurrent);
  1684. /*
  1685. * Get the callers address.
  1686. */
  1687. RtlGetCallersAddress(&ptl->pfnCaller, &pfnT);
  1688. UserAssert(ptl->pW32Thread == (PW32THREAD)ptiCurrent);
  1689. /*
  1690. * Remember the old object.
  1691. */
  1692. UserAssert(ptl->pobj == ptl->ptl->pobj);
  1693. pobjOld = ptl->pobj;
  1694. /*
  1695. * Store and lock the new object. It is important to do this step
  1696. * before unlocking the old object, since the new object might be
  1697. * structure locked by the old object.
  1698. */
  1699. ptl->pobj = pobj;
  1700. if (pobj != NULL) {
  1701. HMLockObject(pobj);
  1702. }
  1703. /*
  1704. * Unlock the old object.
  1705. */
  1706. if (pobjOld) {
  1707. pobjOld = HMUnlockObject((PHEAD)pobjOld);
  1708. }
  1709. /*
  1710. * Validate the entire thread lock list.
  1711. */
  1712. ValidateThreadLocks(NULL, ptiCurrent->ptl, (ULONG_PTR)&pobj, TRUE);
  1713. /*
  1714. * Maintain gFreeTLList
  1715. */
  1716. UserAssert(ptl->ptl->ptl == ptl);
  1717. ptl->ptl->pobj = pobj;
  1718. ptl->ptl->pfnCaller = ptl->pfnCaller;
  1719. return pobjOld;
  1720. }
  1721. #endif
  1722. /*
  1723. * The thread locking routines should be optimized for time, not size,
  1724. * since they get called so often.
  1725. */
  1726. #pragma optimize("t", on)
  1727. /***************************************************************************\
  1728. * ThreadUnlock1
  1729. *
  1730. * This api unlocks a thread locked object. Returns pobj if the object
  1731. * was *not* destroyed (meaning the pointer is still valid).
  1732. *
  1733. * N.B. In a free build the first entry in the thread lock list is unlocked.
  1734. *
  1735. * 03-04-92 ScottLu Created.
  1736. \***************************************************************************/
  1737. #if DBG
  1738. PVOID
  1739. ThreadUnlock1(
  1740. PTL ptlIn)
  1741. #else
  1742. PVOID
  1743. ThreadUnlock1(
  1744. VOID)
  1745. #endif
  1746. {
  1747. PHEAD phead;
  1748. PTHREADINFO ptiCurrent;
  1749. PTL ptl;
  1750. ptiCurrent = PtiCurrent();
  1751. ptl = ptiCurrent->ptl;
  1752. UserAssert(ptl != NULL);
  1753. /*
  1754. * Validate the thread lock list.
  1755. */
  1756. ValidateThreadLocks(NULL, ptl, (ULONG_PTR)&ptlIn, TRUE);
  1757. /*
  1758. * Make sure the caller wants to unlock the top lock.
  1759. */
  1760. UserAssert(ptlIn == ptl);
  1761. ptiCurrent->ptl = ptl->next;
  1762. /*
  1763. * If the object address is not NULL, then unlock the object.
  1764. */
  1765. phead = (PHEAD)(ptl->pobj);
  1766. if (phead != NULL) {
  1767. /*
  1768. * Unlock the object.
  1769. */
  1770. phead = (PHEAD)HMUnlockObject(phead);
  1771. }
  1772. #if DBG
  1773. {
  1774. /*
  1775. * Remove the corresponding element from gFreeTLList
  1776. */
  1777. ptl->ptl->next = gFreeTLList;
  1778. ptl->ptl->uTLCount += TL_FREED_PATTERN;
  1779. gFreeTLList = ptl->ptl;
  1780. }
  1781. #endif
  1782. return (PVOID)phead;
  1783. }
  1784. /*
  1785. * Switch back to default optimization.
  1786. */
  1787. #pragma optimize("", on)
  1788. #if DBG
  1789. /***************************************************************************\
  1790. * CheckLock
  1791. *
  1792. * This routine only exists in DBG builds - it checks to make sure objects
  1793. * are thread locked.
  1794. *
  1795. * 03-09-92 ScottLu Created.
  1796. \***************************************************************************/
  1797. VOID CheckLock(
  1798. PVOID pobj)
  1799. {
  1800. PTHREADINFO ptiCurrent = PtiCurrentShared();
  1801. PTL ptl;
  1802. if (pobj == NULL) {
  1803. return;
  1804. }
  1805. /*
  1806. * Validate all locks first
  1807. */
  1808. UserAssert(ptiCurrent != NULL);
  1809. ValidateThreadLocks(NULL, ptiCurrent->ptl, (ULONG_PTR)&pobj, TRUE);
  1810. for (ptl = ptiCurrent->ptl; ptl != NULL; ptl=ptl->next) {
  1811. if (ptl->pobj == pobj)
  1812. return;
  1813. }
  1814. /*
  1815. * WM_FINALDESTROY messages get sent without thread locking, so if
  1816. * marked for destruction, don't print the message.
  1817. */
  1818. if (HMPheFromObject(pobj)->bFlags & HANDLEF_DESTROY)
  1819. return;
  1820. RIPMSG1(RIP_ERROR, "Object not thread locked! %#p", pobj);
  1821. }
  1822. #endif
  1823. /***************************************************************************\
  1824. * HMDestroyUnlockedObject
  1825. *
  1826. * Destroy an object based on an unlock or cleanup from thread or
  1827. * process termination.
  1828. *
  1829. * The functions called to destroy a particular object can be called
  1830. * directly from code as well as the result of an unlock. Destroy
  1831. * functions have the following 4 sections.
  1832. *
  1833. * (1) Remove the object from a list or other global
  1834. * context. If the destroy function has to leave the
  1835. * critical section (e.g. make an xxx call), it must
  1836. * do so in this step.
  1837. *
  1838. * (2) Call HMMarkDestroy, and return if HMMarkDestroy
  1839. * returns FALSE. This is required.
  1840. *
  1841. * (3) Destroy resources held by the objects - locks to
  1842. * other objects, alloc'd memory, etc. This is required.
  1843. *
  1844. * (4) Free the memory of the object and its handle by calling
  1845. * HMFreeObject. This is required.
  1846. *
  1847. * Note that if the object is locked when it's destroy function
  1848. * is called directly, step (1) will be repeated when the object is
  1849. * unlocked. We should probably check for this in the destroy functions,
  1850. * which we currently do not do.
  1851. *
  1852. * Note that we could be destroying this object in a context different
  1853. * than the one that created it. This is very important to understand
  1854. * since in lots of code the "current thread" is referenced and assumed
  1855. * as the creator.
  1856. *
  1857. * 02-10-92 ScottLu Created.
  1858. \***************************************************************************/
  1859. VOID HMDestroyUnlockedObject(
  1860. PHE phe)
  1861. {
  1862. BEGINATOMICCHECK();
  1863. /*
  1864. * Remember that we're destroying this object so we don't try to destroy
  1865. * it again when the lock count goes from != 0 to 0 (especially true
  1866. * for thread locks).
  1867. */
  1868. phe->bFlags |= HANDLEF_INDESTROY;
  1869. /*
  1870. * This'll call the destroy handler for this object type.
  1871. */
  1872. (*gahti[phe->bType].fnDestroy)(phe->phead);
  1873. /*
  1874. * HANDLEF_INDESTROY is supposed to be cleared either by HMMarkObjectDestroy
  1875. * or by HMFreeObject; the destroy handler was supposed to call at least
  1876. * the former.
  1877. */
  1878. UserAssert(!(phe->bFlags & HANDLEF_INDESTROY));
  1879. /*
  1880. * If the object wasn't freed, it must be marked as destroyed
  1881. * and must have a lock count.
  1882. */
  1883. UserAssert((phe->bType == TYPE_FREE)
  1884. || ((phe->bFlags & HANDLEF_DESTROY) && (phe->phead->cLockObj > 0)));
  1885. ENDATOMICCHECK();
  1886. }
  1887. /***************************************************************************\
  1888. * HMChangeOwnerThread
  1889. *
  1890. * Changes the owning thread of an object.
  1891. *
  1892. * 09-13-93 JimA Created.
  1893. \***************************************************************************/
  1894. VOID HMChangeOwnerThread(
  1895. PVOID pobj,
  1896. PTHREADINFO pti)
  1897. {
  1898. PHE phe = HMPheFromObject(pobj);
  1899. PTHREADINFO ptiOld = ((PTHROBJHEAD)pobj)->pti;
  1900. PWND pwnd;
  1901. PPCLS ppcls;
  1902. PPROCESSINFO ppi;
  1903. CheckCritIn();
  1904. UserAssert(HMObjectFlags(pobj) & OCF_THREADOWNED);
  1905. UserAssert(pti != NULL);
  1906. ((PTHREADINFO)phe->pOwner)->ppi->UserHandleCount--;
  1907. ((PTHROBJHEAD)pobj)->pti = phe->pOwner = pti;
  1908. ((PTHREADINFO)phe->pOwner)->ppi->UserHandleCount++;
  1909. DBGValidateHandleQuota();
  1910. /*
  1911. * If this is a window, update the window counts.
  1912. */
  1913. switch (phe->bType) {
  1914. case TYPE_WINDOW:
  1915. /*
  1916. * Desktop thread used to hit this assert in HYDRA because
  1917. * pti == ptiOld.
  1918. */
  1919. UserAssert(ptiOld->cWindows > 0 || ptiOld == pti);
  1920. pti->cWindows++;
  1921. ptiOld->cWindows--;
  1922. pwnd = (PWND)pobj;
  1923. /*
  1924. * Make sure thread visible window count is properly updated.
  1925. */
  1926. if (TestWF(pwnd, WFVISIBLE) && FVisCountable(pwnd)) {
  1927. pti->cVisWindows++;
  1928. ptiOld->cVisWindows--;
  1929. }
  1930. /*
  1931. * If the owning process is changing, fix up the window class.
  1932. */
  1933. if (pti->ppi != ptiOld->ppi) {
  1934. ppcls = GetClassPtr(pwnd->pcls->atomClassName, pti->ppi, hModuleWin);
  1935. if (ppcls == NULL) {
  1936. if (pwnd->head.rpdesk) {
  1937. ppi = pwnd->head.rpdesk->rpwinstaParent->pTerm->ptiDesktop->ppi;
  1938. } else {
  1939. ppi = PpiCurrent();
  1940. }
  1941. ppcls = GetClassPtr(gpsi->atomSysClass[ICLS_ICONTITLE], ppi, hModuleWin);
  1942. }
  1943. UserAssert(ppcls);
  1944. #if DBG
  1945. if (!TestWF(pwnd, WFDESTROYED)) {
  1946. if ((*ppcls)->rpdeskParent == NULL) {
  1947. /*
  1948. * If rpdeskParent NULL then it has to be a system thread.
  1949. */
  1950. UserAssert(pti->TIF_flags & TIF_SYSTEMTHREAD);
  1951. } else {
  1952. /*
  1953. * The desktop of the class has to be the same as the window's desktop
  1954. */
  1955. UserAssert((*ppcls)->rpdeskParent == pwnd->head.rpdesk);
  1956. }
  1957. }
  1958. #endif
  1959. {
  1960. DereferenceClass(pwnd);
  1961. pwnd->pcls = *ppcls;
  1962. /*
  1963. * We might fail to clone the class for a zombie window in
  1964. * ReferenceClass since we ran out of desktop heap (see bug
  1965. * #375171). In this case, we just increment the class window
  1966. * reference since there will be no client-side reference to
  1967. * the class. Need to assert that the window is destroyed or
  1968. * we will be in trouble. A better fix would be to clone the
  1969. * icon title class beforehand during desktop creation.
  1970. * [msadek, 06/21/2001]
  1971. */
  1972. if (!ReferenceClass(pwnd->pcls, pwnd)) {
  1973. pwnd->pcls->cWndReferenceCount++;
  1974. if (!TestWF(pwnd, WFDESTROYED)) {
  1975. FRE_RIPMSG2(RIP_ERROR,
  1976. "Non destroyed window using a non cloned class. cls 0x%p, pwnd 0x%p",
  1977. pwnd->pcls,
  1978. pwnd);
  1979. }
  1980. }
  1981. }
  1982. }
  1983. break;
  1984. case TYPE_HOOK:
  1985. /*
  1986. * If this is a global hook, remember this hook's desktop so we'll be
  1987. * able to unlink it later (gptiRit might switch to a different desktop
  1988. * at any time).
  1989. */
  1990. UserAssert(!!(((PHOOK)pobj)->flags & HF_GLOBAL) ^ (((PHOOK)pobj)->ptiHooked != NULL));
  1991. if (((PHOOK)pobj)->flags & HF_GLOBAL) {
  1992. UserAssert(pti == gptiRit);
  1993. LockDesktop(&((PHOOK)pobj)->rpdesk, ptiOld->rpdesk, LDL_HOOK_DESK, 0);
  1994. } else {
  1995. /*
  1996. * This must be a hook on another thread or it was supposed to be
  1997. * gone by now.
  1998. */
  1999. UserAssert(((PHOOK)pobj)->ptiHooked != ptiOld);
  2000. }
  2001. break;
  2002. default:
  2003. break;
  2004. }
  2005. }
  2006. /***************************************************************************\
  2007. * HMChangeOwnerProcess
  2008. *
  2009. * Changes the owning process of an object.
  2010. *
  2011. * 04-15-97 JerrySh Created.
  2012. * 09-23-97 GerardoB Changed parameters (and name) so HMDestroyUnlockedObject
  2013. * could use this function (instead of duplicating the code there)
  2014. \***************************************************************************/
  2015. VOID HMChangeOwnerPheProcess(
  2016. PHE phe,
  2017. PTHREADINFO pti)
  2018. {
  2019. PPROCESSINFO ppiOwner = (PPROCESSINFO)(phe->pOwner);
  2020. PVOID pobj = phe->phead;
  2021. UserAssert(HMObjectFlags(pobj) & OCF_PROCESSOWNED);
  2022. UserAssert(pti != NULL);
  2023. /*
  2024. * Dec current owner handle count
  2025. */
  2026. ppiOwner->UserHandleCount--;
  2027. /*
  2028. * hTaskWow
  2029. */
  2030. if ((pti->TIF_flags & TIF_16BIT) && (pti->ptdb)) {
  2031. ((PPROCOBJHEAD)pobj)->hTaskWow = pti->ptdb->hTaskWow;
  2032. } else {
  2033. ((PPROCOBJHEAD)pobj)->hTaskWow = 0;
  2034. }
  2035. /*
  2036. * ppi
  2037. */
  2038. if (gahti[phe->bType].bObjectCreateFlags & OCF_MARKPROCESS) {
  2039. ((PPROCMARKHEAD)pobj)->ppi = pti->ppi;
  2040. }
  2041. /*
  2042. * Set new owner in handle entry
  2043. */
  2044. phe->pOwner = pti->ppi;
  2045. /*
  2046. * Inc new owner handle count
  2047. */
  2048. ((PPROCESSINFO)(phe->pOwner))->UserHandleCount++;
  2049. /*
  2050. * If the handle is a cursor, adjust GDI cursor handle count
  2051. */
  2052. if (phe->bType == TYPE_CURSOR) {
  2053. GreDecQuotaCount((PW32PROCESS)ppiOwner);
  2054. GreIncQuotaCount((PW32PROCESS)phe->pOwner);
  2055. if (((PCURSOR)pobj)->hbmColor) {
  2056. GreDecQuotaCount((PW32PROCESS)ppiOwner);
  2057. GreIncQuotaCount((PW32PROCESS)phe->pOwner);
  2058. }
  2059. if (((PCURSOR)pobj)->hbmUserAlpha) {
  2060. GreDecQuotaCount((PW32PROCESS)ppiOwner);
  2061. GreIncQuotaCount((PW32PROCESS)phe->pOwner);
  2062. }
  2063. }
  2064. DBGValidateHandleQuota();
  2065. }
  2066. /***************************************************************************\
  2067. * DestroyThreadsObjects
  2068. *
  2069. * Goes through the handle table list and destroy all objects owned by this
  2070. * thread, because the thread is going away (either nicely, it faulted, or
  2071. * was terminated). It is ok to destroy the objects in any order, because
  2072. * object locking will ensure that they get destroyed in the right order.
  2073. *
  2074. * This routine gets called in the context of the thread that is exiting.
  2075. *
  2076. * 02-08-92 ScottLu Created.
  2077. \***************************************************************************/
  2078. VOID DestroyThreadsObjects(
  2079. VOID)
  2080. {
  2081. PTHREADINFO ptiCurrent;
  2082. HANDLEENTRY volatile * (*pphe);
  2083. PHE pheT;
  2084. DWORD i;
  2085. ptiCurrent = PtiCurrent();
  2086. DBGValidateHandleQuota();
  2087. /*
  2088. * Before any window destruction occurs, we need to destroy any dcs
  2089. * in use in the dc cache. When a dc is checked out, it is marked owned,
  2090. * which makes gdi's process cleanup code delete it when a process
  2091. * goes away. We need to similarly destroy the cache entry of any dcs
  2092. * in use by the exiting process.
  2093. */
  2094. DestroyCacheDCEntries(ptiCurrent);
  2095. /*
  2096. * Remove any thread locks that may exist for this thread.
  2097. */
  2098. while (ptiCurrent->ptl != NULL) {
  2099. UserAssert((ULONG_PTR)ptiCurrent->ptl > (ULONG_PTR)&i);
  2100. UserAssert((ULONG_PTR)ptiCurrent->ptl < (ULONG_PTR)PsGetCurrentThreadStackBase());
  2101. ThreadUnlock(ptiCurrent->ptl);
  2102. }
  2103. /*
  2104. * CleanupPool stuff must happen before handle table clean up (as it
  2105. * always has been). This is because SMWPs can be HM objects and still
  2106. * be locked in ptlPool. If the handle is destroyed first (and it's not
  2107. * locked) we would end up with a bogus pointer in ptlPool. If ptlPool
  2108. * is cleaned up first, the handle will be freed or properly preserved
  2109. * if locked.
  2110. */
  2111. CleanupW32ThreadLocks((PW32THREAD)ptiCurrent);
  2112. /*
  2113. * Even though HMDestroyUnlockedObject might call xxxDestroyWindow, the
  2114. * following loop is not supposed to leave the critical section. We must
  2115. * have called PatchThreadWindows before coming here.
  2116. */
  2117. BEGINATOMICCHECK();
  2118. /*
  2119. * Loop through the table destroying all objects created by the current
  2120. * thread. All objects will get destroyed in their proper order simply
  2121. * because of the object locking.
  2122. */
  2123. pphe = &gSharedInfo.aheList;
  2124. for (i = 0; i <= giheLast; i++) {
  2125. /*
  2126. * This pointer is done this way because it can change when we leave
  2127. * the critical section below. The above volatile ensures that we
  2128. * always use the most current value
  2129. */
  2130. pheT = (PHE)((*pphe) + i);
  2131. /*
  2132. * Check against free before we look at pti... because pq is stored
  2133. * in the object itself, which won't be there if TYPE_FREE.
  2134. */
  2135. if (pheT->bType == TYPE_FREE) {
  2136. continue;
  2137. }
  2138. /*
  2139. * If a menu refererences a window owned by this thread, unlock
  2140. * the window. This is done to prevent calling xxxDestroyWindow
  2141. * during process cleanup.
  2142. */
  2143. if (gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) {
  2144. if (pheT->bType == TYPE_MENU) {
  2145. PWND pwnd = ((PMENU)pheT->phead)->spwndNotify;
  2146. if (pwnd != NULL && GETPTI(pwnd) == ptiCurrent) {
  2147. Unlock(&((PMENU)pheT->phead)->spwndNotify);
  2148. }
  2149. }
  2150. continue;
  2151. }
  2152. /*
  2153. * Destroy those objects created by this queue.
  2154. */
  2155. if ((PTHREADINFO)pheT->pOwner != ptiCurrent) {
  2156. continue;
  2157. }
  2158. UserAssert(gahti[pheT->bType].bObjectCreateFlags & OCF_THREADOWNED);
  2159. /*
  2160. * Make sure this object isn't already marked to be destroyed - we'll
  2161. * do no good if we try to destroy it now since it is locked.
  2162. */
  2163. if (pheT->bFlags & HANDLEF_DESTROY) {
  2164. continue;
  2165. }
  2166. /*
  2167. * Destroy this object.
  2168. */
  2169. HMDestroyUnlockedObject(pheT);
  2170. }
  2171. ENDATOMICCHECK();
  2172. DBGValidateHandleQuota();
  2173. }
  2174. #if DBG || FRE_LOCK_RECORD
  2175. VOID ShowLocks(
  2176. PHE phe)
  2177. {
  2178. PLR plr = phe->plr;
  2179. INT c;
  2180. RIPMSG2(RIP_WARNING | RIP_THERESMORE,
  2181. "Lock records for %s %#p:",
  2182. gahti[phe->bType].szObjectType, phe->phead->h);
  2183. /*
  2184. * We have the handle entry: 'head' and 'he' are both filled in. Dump
  2185. * the lock records. Remember the first record is the last transaction!!
  2186. */
  2187. c = 0;
  2188. while (plr != NULL) {
  2189. char achPrint[80];
  2190. if (plr->ppobj == LOCKRECORD_MARKDESTROY) {
  2191. strcpy(achPrint, "Destroyed with");
  2192. } else if ((int)plr->cLockObj <= 0) {
  2193. strcpy(achPrint, " Unlock");
  2194. } else {
  2195. /*
  2196. * Find corresponding unlock;
  2197. */
  2198. {
  2199. PLR plrUnlock;
  2200. DWORD cT;
  2201. DWORD cUnlock;
  2202. plrUnlock = phe->plr;
  2203. cT = 0;
  2204. cUnlock = (DWORD)-1;
  2205. while (plrUnlock != plr) {
  2206. if (plrUnlock->ppobj == plr->ppobj) {
  2207. if ((int)plrUnlock->cLockObj <= 0) {
  2208. // a matching unlock found
  2209. cUnlock = cT;
  2210. } else {
  2211. // the unlock #cUnlock matches this lock #cT, thus
  2212. // #cUnlock is not the unlock we were looking for.
  2213. cUnlock = (DWORD)-1;
  2214. }
  2215. }
  2216. plrUnlock = plrUnlock->plrNext;
  2217. cT++;
  2218. }
  2219. if (cUnlock == (DWORD)-1) {
  2220. /*
  2221. * Corresponding unlock not found!
  2222. * This may not mean something is wrong: the structure
  2223. * containing the pointer to the object may have moved
  2224. * during a reallocation. This can cause ppobj at Unlock
  2225. * time to differ from that recorded at Lock time.
  2226. * (Warning: moving structures like this may cause a Lock
  2227. * and an Unlock to be misidentified as a pair, if by a
  2228. * stroke of incredibly bad luck, the new location of a
  2229. * pointer to an object is now where an old pointer to the
  2230. * same object used to be)
  2231. */
  2232. sprintf(achPrint, "Unmatched Lock");
  2233. } else {
  2234. sprintf(achPrint, "lock #%ld", cUnlock);
  2235. }
  2236. }
  2237. }
  2238. RIPMSG4(RIP_WARNING | RIP_NONAME | RIP_THERESMORE,
  2239. " %s cLock=%d, pobj at %#p, code at %#p",
  2240. achPrint,
  2241. abs((int)plr->cLockObj),
  2242. plr->ppobj,
  2243. plr->trace[0]);
  2244. plr = plr->plrNext;
  2245. c++;
  2246. }
  2247. RIPMSG1(RIP_WARNING | RIP_NONAME, " 0x%lx records", c);
  2248. }
  2249. #endif
  2250. /***************************************************************************\
  2251. * FixupGlobalCursor
  2252. *
  2253. * Spins through a global cursor (a cursor who's owner is NULL), and
  2254. * reassigns ownership to the specified process.
  2255. *
  2256. * Note: This changes the owner process field inside the object itself. It
  2257. * does not change the owner field of the handle referencing it.
  2258. *
  2259. \***************************************************************************/
  2260. VOID FixupGlobalCursor(
  2261. PCURSOR pcur,
  2262. PPROCESSINFO ppi)
  2263. {
  2264. int i;
  2265. PACON pacon = (PACON)pcur;
  2266. if (pcur->head.ppi == NULL) {
  2267. pcur->head.ppi = ppi;
  2268. }
  2269. if (pacon->CURSORF_flags & CURSORF_ACON) {
  2270. for (i = 0; i < pacon->cpcur; i++) {
  2271. UserAssert(pacon->aspcur[i]->CURSORF_flags & CURSORF_ACONFRAME);
  2272. if (pacon->aspcur[i]->head.ppi == NULL) {
  2273. pacon->aspcur[i]->head.ppi = ppi;
  2274. }
  2275. }
  2276. }
  2277. }
  2278. /***************************************************************************\
  2279. * DestroyProcessesObjects
  2280. *
  2281. * Goes through the handle table list and destroy all objects owned by this
  2282. * process, because the process is going away (either nicely, it faulted, or
  2283. * was terminated). It is ok to destroy the objects in any order, because
  2284. * object locking will ensure that they get destroyed in the right order.
  2285. *
  2286. * This routine gets called in the context of the last thread in the process.
  2287. *
  2288. * 08-17-92 JimA Created.
  2289. \***************************************************************************/
  2290. VOID DestroyProcessesObjects(
  2291. PPROCESSINFO ppi)
  2292. {
  2293. PHE pheT, pheMax;
  2294. BOOL fCSRSS = (ppi->Process == gpepCSRSS);
  2295. #if DBG
  2296. BOOL fOrphaned = FALSE;
  2297. #endif // DBG
  2298. DBGValidateHandleQuota();
  2299. /*
  2300. * Loop through the table destroying all objects owned by the current
  2301. * process. All objects will get destroyed in their proper order simply
  2302. * because of the object locking.
  2303. */
  2304. pheMax = &gSharedInfo.aheList[giheLast];
  2305. for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
  2306. /*
  2307. * If this handle entry is free, skip it.
  2308. */
  2309. if (pheT->bType == TYPE_FREE) {
  2310. continue;
  2311. }
  2312. /*
  2313. * Don't destroy objects that are either not owned by a process at all, or
  2314. * are owned by a process - but a different process than us!
  2315. */
  2316. if (!(gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) ||
  2317. (PPROCESSINFO)pheT->pOwner != ppi) {
  2318. continue;
  2319. }
  2320. /*
  2321. * If this is CSRSS being destroyed, then we need to clean up all
  2322. * "global" cursors. Note that the owner process stored in the
  2323. * handle is CSRSS, but the owner process stored in the object is
  2324. * NULL. We assign ownership of the cursor (and all associated
  2325. * frames) to CSRSS, so that it will be cleaned up during the
  2326. * HMDestroyUnlockedObject call.
  2327. */
  2328. if (fCSRSS && pheT->bType == TYPE_CURSOR) {
  2329. FixupGlobalCursor((PCURSOR)pheT->phead, ppi);
  2330. }
  2331. /*
  2332. * Destroy this object - but only if it hasn't already been destroyed!
  2333. */
  2334. if (!(pheT->bFlags & HANDLEF_DESTROY)) {
  2335. HMDestroyUnlockedObject(pheT);
  2336. } else {
  2337. //
  2338. // If the handle was marked as having already been destroyed, it
  2339. // should have a non-zero lock count. When the final Unlock is
  2340. // called, the object will be freed.
  2341. //
  2342. UserAssert(pheT->phead->cLockObj != 0);
  2343. }
  2344. /*
  2345. * Check to see if the object was destroyed, but not freed.
  2346. */
  2347. if (pheT->bType != TYPE_FREE) {
  2348. /*
  2349. * This object has already been destroyed. Is is just waiting for its
  2350. * lock count to reach 0 before it can be actually freed. However,
  2351. * since this object is owned by the process that is going away, it
  2352. * is now an "orphaned" object. Pass ownership to the RIT if possible.
  2353. * Once the other objects that are holding locks on this object release
  2354. * their locks, this object will evaporate. If the locks are never
  2355. * released then we have a leak, and we will catch it later.
  2356. *
  2357. * Note that this might be uneccessary, as the owners of the locks
  2358. * may all belong to this process, and as such will all be destroyed
  2359. * during this function - and therefore the reparenting was not needed.
  2360. * However, doing so now allows us to complete in a single pass
  2361. * through the handle table.
  2362. */
  2363. if (gptiRit != NULL) {
  2364. if (pheT->bType == TYPE_CURSOR) {
  2365. ZombieCursor((PCURSOR)pheT->phead);
  2366. } else {
  2367. HMChangeOwnerPheProcess(pheT, gptiRit);
  2368. }
  2369. }
  2370. #if DBG
  2371. fOrphaned = TRUE;
  2372. #endif // DBG
  2373. }
  2374. }
  2375. #if DBG
  2376. /*
  2377. * Check to see if we have any orphans left in the handle table that
  2378. * used to belong to this process. This only poses a serious problem
  2379. * when the RIT is not available (for instance, if we are shutting down)
  2380. * because we have no one to adopt these objects. This would indicate
  2381. * a serious resource leak and should be fixed.
  2382. */
  2383. if (fOrphaned && gptiRit == NULL) {
  2384. pheMax = &gSharedInfo.aheList[giheLast];
  2385. for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
  2386. if (pheT->bType != TYPE_FREE &&
  2387. (gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) &&
  2388. (PPROCESSINFO)pheT->pOwner == ppi) {
  2389. RIPMSGF1(RIP_ERROR, "Object leak detected! phe= 0x%p", pheT);
  2390. }
  2391. }
  2392. }
  2393. #endif
  2394. DBGValidateHandleQuota();
  2395. }
  2396. /***************************************************************************\
  2397. * MarkThreadsObjects
  2398. *
  2399. * This is called for the *final* exiting condition when a thread
  2400. * may have objects still around... in which case their owner must
  2401. * be changed to something "safe" that won't be going away.
  2402. *
  2403. * 03-02-92 ScottLu Created.
  2404. \***************************************************************************/
  2405. VOID MarkThreadsObjects(
  2406. PTHREADINFO pti)
  2407. {
  2408. PHE pheT, pheMax;
  2409. pheMax = &gSharedInfo.aheList[giheLast];
  2410. for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
  2411. /*
  2412. * Check against free before we look at pti... because pti is stored
  2413. * in the object itself, which won't be there if TYPE_FREE.
  2414. */
  2415. if (pheT->bType == TYPE_FREE) {
  2416. continue;
  2417. }
  2418. /*
  2419. * Change ownership!
  2420. */
  2421. if (gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED ||
  2422. (PTHREADINFO)pheT->pOwner != pti) {
  2423. continue;
  2424. }
  2425. /*
  2426. * This is just to make sure that RIT or DT never get here.
  2427. */
  2428. UserAssert(pti != gptiRit && pti != gTermIO.ptiDesktop);
  2429. HMChangeOwnerThread(pheT->phead, gptiRit);
  2430. #if DBG
  2431. if (IsDbgTagEnabled(DBGTAG_TrackLocks)) {
  2432. /*
  2433. * Object still around: print warning message.
  2434. */
  2435. if (pheT->bFlags & HANDLEF_DESTROY) {
  2436. TAGMSG2(DBGTAG_TrackLocks,
  2437. "Zombie %s 0x%p still locked",
  2438. gahti[pheT->bType].szObjectType,
  2439. pheT->phead->h);
  2440. } else {
  2441. TAGMSG1(DBGTAG_TrackLocks,
  2442. "Thread object 0x%p not destroyed.",
  2443. pheT->phead->h);
  2444. }
  2445. ShowLocks(pheT);
  2446. }
  2447. #endif
  2448. }
  2449. }
  2450. /***************************************************************************\
  2451. * HMRelocateLockRecord
  2452. *
  2453. * If a pointer to a locked object has been relocated, then this routine will
  2454. * adjust the lock record accordingly. Must be called after the relocation.
  2455. *
  2456. * The arguments are:
  2457. * ppobjNew - the address of the new pointer
  2458. * MUST already contain the pointer to the object!!
  2459. * cbDelta - the amount by which this pointer was moved.
  2460. *
  2461. * Using this routine appropriately will prevent spurious "unmatched lock"
  2462. * reports. See mnchange.c for an example.
  2463. *
  2464. *
  2465. * 03-18-93 IanJa Created.
  2466. \***************************************************************************/
  2467. #if DBG || FRE_LOCK_RECORD
  2468. BOOL HMRelocateLockRecord(
  2469. PVOID ppobjNew,
  2470. LONG_PTR cbDelta)
  2471. {
  2472. PHE phe;
  2473. PVOID ppobjOld = (PBYTE)ppobjNew - cbDelta;
  2474. PHEAD pobj;
  2475. PLR plr;
  2476. if (ppobjNew == NULL) {
  2477. return FALSE;
  2478. }
  2479. pobj = *(PHEAD *)ppobjNew;
  2480. if (pobj == NULL) {
  2481. return FALSE;
  2482. }
  2483. phe = HMPheFromObject(pobj);
  2484. if (phe->phead != pobj) {
  2485. RIPMSG3(RIP_WARNING,
  2486. "HmRelocateLockRecord(%#p, %lx) - %#p is bad pobj",
  2487. ppobjNew, cbDelta, pobj);
  2488. return FALSE;
  2489. }
  2490. plr = phe->plr;
  2491. while (plr != NULL) {
  2492. if (plr->ppobj == ppobjOld) {
  2493. (PBYTE)(plr->ppobj) += cbDelta;
  2494. return TRUE;
  2495. }
  2496. plr = plr->plrNext;
  2497. }
  2498. RIPMSG2(RIP_WARNING,
  2499. "HmRelocateLockRecord(%#p, %lx) - couldn't find lock record",
  2500. ppobjNew, cbDelta);
  2501. ShowLocks(phe);
  2502. return FALSE;
  2503. }
  2504. BOOL HMUnrecordLock(
  2505. PVOID ppobj,
  2506. PVOID pobj)
  2507. {
  2508. PHE phe;
  2509. PLR plr;
  2510. PLR *pplr;
  2511. phe = HMPheFromObject(pobj);
  2512. pplr = &(phe->plr);
  2513. plr = *pplr;
  2514. /*
  2515. * Find corresponding lock;
  2516. */
  2517. while (plr != NULL) {
  2518. if (plr->ppobj == ppobj) {
  2519. /*
  2520. * Remove the lock from the list...
  2521. */
  2522. *pplr = plr->plrNext; // unlink it
  2523. plr->plrNext = NULL; // make the dead entry safe (?)
  2524. /*
  2525. * ...and free it.
  2526. */
  2527. FreeLockRecord(plr);
  2528. return TRUE;
  2529. }
  2530. pplr = &(plr->plrNext);
  2531. plr = *pplr;
  2532. }
  2533. RIPMSG2(RIP_WARNING, "Could not find lock for ppobj %#p pobj %#p",
  2534. ppobj, pobj);
  2535. return FALSE;
  2536. }
  2537. #endif // DBG
  2538. /***************************************************************************\
  2539. * _QueryUserHandles
  2540. *
  2541. * This function retrieves the USER handle counters for all processes
  2542. * specified by their client ID in the paPids array
  2543. * Specify QUC_PID_TOTAL to retrieve totals for all processes in the system
  2544. *
  2545. * Parameters:
  2546. * paPids - pointer to an array of pids (DWORDS) that we're interested in
  2547. * dwNumInstances - number of DWORDS in paPids
  2548. * pdwResult - will receive TYPES_CTYPESxdwNumInstances counters
  2549. *
  2550. * returns: none
  2551. *
  2552. * 07-25-97 mcostea Created
  2553. \***************************************************************************/
  2554. VOID _QueryUserHandles(
  2555. LPDWORD paPids,
  2556. DWORD dwNumInstances,
  2557. DWORD dwResult[][TYPE_CTYPES])
  2558. {
  2559. PHE pheCurPos; // Current position in the table
  2560. PHE pheMax; // address of last table entry
  2561. DWORD index;
  2562. DWORD pid;
  2563. DWORD dwTotalCounters[TYPE_CTYPES]; // system wide counters
  2564. RtlZeroMemory(dwTotalCounters, TYPE_CTYPES*sizeof(DWORD));
  2565. RtlZeroMemory(dwResult, dwNumInstances*TYPE_CTYPES*sizeof(DWORD));
  2566. /*
  2567. * Walk the handle table and update the counters
  2568. */
  2569. pheMax = &gSharedInfo.aheList[giheLast];
  2570. for(pheCurPos = gSharedInfo.aheList; pheCurPos <= pheMax; pheCurPos++) {
  2571. UserAssert(pheCurPos->bType < TYPE_CTYPES);
  2572. if (pheCurPos->pOwner) {
  2573. if (gahti[pheCurPos->bType].bObjectCreateFlags & OCF_PROCESSOWNED) {
  2574. pid = HandleToUlong(PsGetProcessId(((PPROCESSINFO)(pheCurPos->pOwner))->Process));
  2575. } else if (gahti[pheCurPos->bType].bObjectCreateFlags & OCF_THREADOWNED) {
  2576. pid = HandleToUlong(PsGetThreadProcessId(((PTHREADINFO)pheCurPos->pOwner)->pEThread));
  2577. } else {
  2578. pid = 0;
  2579. }
  2580. }
  2581. /*
  2582. * Search to see if we are interested in this process. Unowned
  2583. * handles are reported for the "System" process whose pid is 0.
  2584. */
  2585. for (index = 0; index < dwNumInstances; index++) {
  2586. if (paPids[index] == pid) {
  2587. dwResult[index][pheCurPos->bType]++;
  2588. }
  2589. }
  2590. /*
  2591. * Update the totals.
  2592. */
  2593. dwTotalCounters[pheCurPos->bType]++;
  2594. }
  2595. /*
  2596. * Search to see if we are interested in the totals.
  2597. */
  2598. for (index = 0; index < dwNumInstances; index++) {
  2599. if (paPids[index] == QUC_PID_TOTAL) {
  2600. RtlMoveMemory(dwResult[index], dwTotalCounters, sizeof(dwTotalCounters));
  2601. }
  2602. }
  2603. }
  2604. /***************************************************************************\
  2605. * HMCleanupGrantedHandle
  2606. *
  2607. * This function is called to cleanup this handle from pW32Job->pgh arrays.
  2608. * It walks the job list to find jobs that have the handle granted.
  2609. *
  2610. * HISTORY:
  2611. * 22 Jul 97 CLupu Created
  2612. \***************************************************************************/
  2613. VOID HMCleanupGrantedHandle(
  2614. HANDLE h)
  2615. {
  2616. PW32JOB pW32Job;
  2617. pW32Job = gpJobsList;
  2618. while (pW32Job != NULL) {
  2619. PULONG_PTR pgh;
  2620. DWORD dw;
  2621. pgh = pW32Job->pgh;
  2622. /*
  2623. * search for the handle in the array.
  2624. */
  2625. for (dw = 0; dw < pW32Job->ughCrt; dw++) {
  2626. if (*(pgh + dw) == (ULONG_PTR)h) {
  2627. /*
  2628. * Found the handle granted to this process.
  2629. */
  2630. RtlMoveMemory(pgh + dw,
  2631. pgh + dw + 1,
  2632. (pW32Job->ughCrt - dw - 1) * sizeof(*pgh));
  2633. (pW32Job->ughCrt)--;
  2634. /*
  2635. * we should shrink the array also
  2636. */
  2637. break;
  2638. }
  2639. }
  2640. pW32Job = pW32Job->pNext;
  2641. }
  2642. }