Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

handtabl.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: handtabl.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Implements the USER handle table. 00007 * 00008 * 01-13-92 ScottLu Created. 00009 \***************************************************************************/ 00010 00011 #include "precomp.h" 00012 #pragma hdrstop 00013 00014 #pragma alloc_text(INIT, HMInitHandleTable) 00015 00016 #if DBG 00017 00018 #define HTIENTRY(szObjectType, structName, fnDestroy, dwAllocTag, bObjectCreateFlags) \ 00019 {szObjectType, sizeof(structName), (FnDestroyUserObject)fnDestroy, (CONST DWORD)dwAllocTag, (CONST BYTE)(bObjectCreateFlags)} 00020 00021 #else // DBG 00022 00023 #define HTIENTRY(szObjectType, structName, fnDestroy, dwAllocTag, bObjectCreateFlags) \ 00024 {(FnDestroyUserObject)fnDestroy, (CONST DWORD)dwAllocTag, (CONST BYTE)(bObjectCreateFlags)} 00025 00026 #endif // DBG 00027 00028 void HMNullFnDestroy(PVOID pobj) 00029 { 00030 RIPMSG1(RIP_WARNING, "HM: No clean up function for %#p", pobj); 00031 HMDestroyObject(pobj); 00032 return; 00033 } 00034 /***************************************************************************\ 00035 * 00036 * Table of user objects statistics. Used by userkdx.dumhmgr debugger extension 00037 * 00038 \***************************************************************************/ 00039 00040 #if DBG 00041 00042 /* 00043 * Note that we need to statically initialize gaPrevhti so that it is 00044 * included during the link phase. It is not refered to anywher in win32k.sys, 00045 * only in userkdx.dll, so it will be optimized out in the link phase otherwise. 00046 * Marking it volatile did not seem to help. 00047 */ 00048 00049 PERFHANDLEINFO gaPerfhti[TYPE_CTYPES] = {0}; /* stores current counts */ 00050 PERFHANDLEINFO gaPrevhti[TYPE_CTYPES] = {0}; /* stores previous counts */ 00051 00052 #endif // DBG 00053 00054 /***************************************************************************\ 00055 * 00056 * Table of handle type information. 00057 * 00058 * Desktop and Shared Heap objects can't be tagged as yet 00059 * (TAG_WINDOW is bogus for heap windows, but not for desktop and other 00060 * windows allocated in pool). 00061 * 00062 * WARNING: Keep it in sync with aszTypeNames table from ntuser\kdexts\userexts.c 00063 * 00064 * All HM objects must start with a HEAD strucutre. In addition: 00065 * (If you find these comments to be wrong, please fix them) 00066 * 00067 * OCF_PROCESSOWNED: Object must start with a PROC*HEAD structure 00068 * A ptiOwner must be provided 00069 * The object affects the handle quota (ppi->UserHandleCount) 00070 * The object will be destroyed if the process goes away. 00071 * 00072 * OCF_MARKPROCESS: Object must start with a PROCMARKHEAD structure 00073 * A ptiOwner must be provided 00074 * It must not use OCF_DESKTOPHEAP (implementation limitation) 00075 * 00076 * OCF_THREADOWNED: Object must start with a THR*HEAD structure 00077 * The object affects the handle quota (ppi->UserHandleCount) 00078 * The object will be destroyed if the thread goes away. 00079 * 00080 * OCF_DESKTOPHEAP: Object must start with a *DESKHEAD structure 00081 * A pdeskSrc must be provided at allocation time 00082 * It must not use OCF_MARKPROCESS (implementation limitation) 00083 * 00084 \***************************************************************************/ 00085 00086 #if (TYPE_FREE != 0) 00087 #error TYPE_FREE must be zero. 00088 #endif 00089 00090 CONST HANDLETYPEINFO gahti[TYPE_CTYPES] = { 00091 /* TYPE_FREE - HEAD */ 00092 HTIENTRY("Free", HEAD, 00093 NULL, 00094 0, 00095 0), 00096 00097 /* TYPE_WINDOW - WND(THRDESKHEAD) */ 00098 HTIENTRY("Window", WND, 00099 xxxDestroyWindow, 00100 TAG_WINDOW, 00101 OCF_THREADOWNED | OCF_USEPOOLQUOTA | OCF_DESKTOPHEAP | OCF_USEPOOLIFNODESKTOP | OCF_VARIABLESIZE), 00102 00103 /* TYPE_MENU - MENU(PROCDESKHEAD) */ 00104 HTIENTRY("Menu", MENU, 00105 _DestroyMenu, 00106 0, 00107 OCF_PROCESSOWNED | OCF_DESKTOPHEAP), 00108 00109 /* TYPE_CURSOR - CURSOR(PROCMARKHEAD) or ACON(PROCMARKHEAD) */ 00110 HTIENTRY("Icon/Cursor", CURSOR, 00111 DestroyUnlockedCursor, 00112 TAG_CURSOR, 00113 OCF_PROCESSOWNED | OCF_MARKPROCESS | OCF_USEPOOLQUOTA), 00114 00115 /* TYPE_SETWINDOWPOS - SMWP(HEAD) */ 00116 HTIENTRY("WPI(SWP) structure", SMWP, 00117 DestroySMWP, 00118 TAG_SWP, 00119 OCF_THREADOWNED | OCF_USEPOOLQUOTA), 00120 00121 /* TYPE_HOOK - HOOK(THRDESKHEAD) */ 00122 HTIENTRY("Hook", HOOK, 00123 FreeHook, 00124 0, 00125 OCF_THREADOWNED | OCF_DESKTOPHEAP), 00126 00127 /* TYPE_CLIPDATA - CLIPDATA(HEAD) */ 00128 HTIENTRY("Clipboard Data", CLIPDATA, 00129 HMNullFnDestroy, 00130 TAG_CLIPBOARD, 00131 OCF_VARIABLESIZE), 00132 00133 /* TYPE_CALLPROC - CALLPROCDATA(THRDESKHEAD) */ 00134 HTIENTRY("CallProcData", CALLPROCDATA, 00135 HMDestroyObject, 00136 0, 00137 OCF_PROCESSOWNED | OCF_DESKTOPHEAP), 00138 00139 /* TYPE_ACCELTABLE - ACCELTABLE(PROCOBJHEAD) */ 00140 HTIENTRY("Accelerator", ACCELTABLE, 00141 HMDestroyObject, 00142 TAG_ACCEL, 00143 OCF_PROCESSOWNED | OCF_USEPOOLQUOTA | OCF_VARIABLESIZE), 00144 00145 /* TYPE_DDEACCESS - SVR_INSTANCE_INFO(THROBJHEAD) */ 00146 HTIENTRY("DDE access", SVR_INSTANCE_INFO, 00147 HMNullFnDestroy, 00148 TAG_DDE9, 00149 OCF_THREADOWNED | OCF_USEPOOLQUOTA), 00150 00151 /* TYPE_DDECONV - DDECONV(THROBJHEAD) */ 00152 HTIENTRY("DDE conv", DDECONV, 00153 FreeDdeConv, 00154 TAG_DDEa, 00155 OCF_THREADOWNED | OCF_USEPOOLQUOTA), 00156 00157 /* TYPE_DDEXACT - XSTATE(THROBJHEAD) */ 00158 HTIENTRY("DDE Transaction", XSTATE, 00159 FreeDdeXact, 00160 TAG_DDEb, 00161 OCF_THREADOWNED | OCF_USEPOOLQUOTA), 00162 00163 /* TYPE_MONITOR - MONITOR(HEAD) */ 00164 HTIENTRY("Monitor", MONITOR, 00165 DestroyMonitor, 00166 TAG_DISPLAYINFO, 00167 OCF_SHAREDHEAP), 00168 00169 /* TYPE_KBDLAYOUT - KL(HEAD) */ 00170 HTIENTRY("Keyboard Layout", KL, 00171 DestroyKL, 00172 TAG_KBDLAYOUT, 00173 0), 00174 00175 /* TYPE_KBDFILE - KBDFILE(HEAD) */ 00176 HTIENTRY("Keyboard File", KBDFILE, 00177 DestroyKF, 00178 TAG_KBDFILE, 00179 0), 00180 00181 /* TYPE_WINEVENTHOOK - EVENTHOOK(THROBJHEAD) */ 00182 HTIENTRY("WinEvent hook", EVENTHOOK, 00183 DestroyEventHook, 00184 TAG_WINEVENT, 00185 OCF_THREADOWNED), 00186 00187 00188 /* TYPE_TIMER - TIMER(HEAD) */ 00189 HTIENTRY("Timer", TIMER, 00190 FreeTimer, 00191 TAG_TIMER, 00192 0), 00193 00194 /* TYPE_INPUTCONTEXT - IMC(THRDESKHEAD) */ 00195 HTIENTRY("Input Context", IMC, 00196 FreeInputContext, 00197 0, 00198 OCF_THREADOWNED | OCF_DESKTOPHEAP), 00199 }; 00200 00201 /* 00202 * Handle table allocation globals. The purpose of keeping per-page free 00203 * lists is to keep the table as small as is practical and to minimize 00204 * the number of pages touched while performing handle table operations. 00205 */ 00206 #define CPAGEENTRIESINIT 4 00207 00208 DWORD gcHandlePages; 00209 PHANDLEPAGE gpHandlePages; 00210 00211 #if DBG 00212 PPAGED_LOOKASIDE_LIST LockRecordLookaside; 00213 00214 NTSTATUS InitLockRecordLookaside(); 00215 void FreeLockRecord(PLR plr); 00216 void InitGlobalThreadLockArray(DWORD dwIndex); 00217 #endif 00218 00219 void HMDestroyUnlockedObject(PHE phe); 00220 void HMRecordLock(PVOID ppobj, PVOID pobj, DWORD cLockObj); 00221 BOOL HMUnrecordLock(PVOID ppobj, PVOID pobj); 00222 VOID ShowLocks(PHE); 00223 00224 00225 /***************************************************************************\ 00226 * DBGValidateHandleQuota 00227 * 00228 * 11-19-97 GerardoB Created. 00229 \***************************************************************************/ 00230 #ifdef VALIDATEHANDLEQUOTA 00231 void DBGValidateHandleQuota (void) 00232 { 00233 BYTE bCreateFlags; 00234 DWORD dw; 00235 HANDLEENTRY * phe; 00236 00237 PPROCESSINFO ppiT = gppiList; 00238 00239 while (ppiT != NULL) { 00240 ppiT->lHandles = 0; 00241 ppiT = ppiT->ppiNextRunning; 00242 } 00243 00244 phe = gSharedInfo.aheList; 00245 for (dw = 0; dw <= giheLast; dw++, phe++) { 00246 if (phe->bType == TYPE_FREE) { 00247 UserAssert(phe->pOwner == NULL); 00248 continue; 00249 } 00250 bCreateFlags = gahti[phe->bType].bObjectCreateFlags; 00251 if (bCreateFlags & OCF_PROCESSOWNED) { 00252 ((PPROCESSINFO)phe->pOwner)->lHandles++; 00253 continue; 00254 } 00255 if (bCreateFlags & OCF_THREADOWNED) { 00256 ((PTHREADINFO)phe->pOwner)->ppi->lHandles++; 00257 continue; 00258 } 00259 UserAssert(phe->pOwner == NULL); 00260 } 00261 00262 ppiT = gppiList; 00263 while (ppiT != NULL) { 00264 UserAssert(ppiT->lHandles == ppiT->UserHandleCount); 00265 ppiT = ppiT->ppiNextRunning; 00266 } 00267 } 00268 #else 00269 #define DBGValidateHandleQuota() 00270 #endif 00271 /***************************************************************************\ 00272 * DBGHMPheFromObject 00273 * 00274 * Validates and returns the HANDLEENTRY corresponding to a given object 00275 * 00276 * 09-23-97 GerardoB Created. 00277 \***************************************************************************/ 00278 #if DBG 00279 PHE DBGHMPheFromObject (PVOID p) 00280 { 00281 PHE phe = _HMPheFromObject(p); 00282 00283 UserAssert(phe->phead == p); 00284 UserAssert(_HMObjectFromHandle(phe->phead->h) == p); 00285 UserAssert(phe->wUniq == HMUniqFromHandle(phe->phead->h)); 00286 UserAssert(phe->bType < TYPE_CTYPES); 00287 UserAssert((phe->pOwner != NULL) 00288 || !(gahti[phe->bType].bObjectCreateFlags & (OCF_PROCESSOWNED | OCF_THREADOWNED))); 00289 UserAssert(!(phe->bFlags & ~HANDLEF_VALID)); 00290 00291 return phe; 00292 } 00293 #endif 00294 /***************************************************************************\ 00295 * DBGHMPheFromObject 00296 * 00297 * Validates and returns the object corresponding to a given handle. 00298 * 00299 * 09-23-97 GerardoB Created. 00300 \***************************************************************************/ 00301 #if DBG 00302 PVOID DBGHMObjectFromHandle (HANDLE h) 00303 { 00304 PVOID p = _HMObjectFromHandle(h); 00305 00306 UserAssert((h != NULL) ^ (p == NULL)); 00307 if (p != NULL) { 00308 UserAssert(HMIndexFromHandle(((PHEAD)p)->h) == HMIndexFromHandle(h)); 00309 UserAssert(p == HMRevalidateCatHandle(h)); 00310 /* 00311 * This routine, unlike Validation, should return a real pointer if 00312 * the object exists, even if it is destroyed. But we should still 00313 * generate a warning. 00314 */ 00315 if (HMPheFromObject(p)->bFlags & HANDLEF_DESTROY) { 00316 RIPMSG1(RIP_WARNING, "HMObjectFromHandle: Object p %#p is destroyed", 00317 p); 00318 } 00319 } 00320 00321 return p; 00322 } 00323 PVOID DBGHMCatObjectFromHandle (HANDLE h) 00324 { 00325 /* 00326 * Note -- at this point, _HMObjectFromHandle does not check 00327 * to see if an object is destroyed. 00328 */ 00329 PVOID p = _HMObjectFromHandle(h); 00330 00331 UserAssert((h != NULL) ^ (p == NULL)); 00332 if (p != NULL) { 00333 UserAssert(HMIndexFromHandle(((PHEAD)p)->h) == HMIndexFromHandle(h)); 00334 UserAssert(p == HMRevalidateCatHandle(h)); 00335 } 00336 00337 return p; 00338 } 00339 #endif 00340 /***************************************************************************\ 00341 * DBGPtoH and DBGPtoHq 00342 * 00343 * Validates and returns the handle corresponding to a given object 00344 * 00345 * 09-23-97 GerardoB Created. 00346 \***************************************************************************/ 00347 #if DBG 00348 void DBGValidatePtoH (PVOID p, HANDLE h) 00349 { 00350 UserAssert((h != NULL) ^ (p == NULL)); 00351 if (h != NULL) { 00352 UserAssert(p == HMRevalidateCatHandle(h)); 00353 } 00354 } 00355 HANDLE DBGPtoH (PVOID p) 00356 { 00357 HANDLE h = _PtoH(p); 00358 DBGValidatePtoH(p, h); 00359 return h; 00360 } 00361 HANDLE DBGPtoHq (PVOID p) 00362 { 00363 HANDLE h; 00364 UserAssert(p != NULL); 00365 h = _PtoHq(p); 00366 DBGValidatePtoH(p, h); 00367 return h; 00368 } 00369 #endif 00370 /***************************************************************************\ 00371 * DBGHW and DBGHWq 00372 * 00373 * Validates and returns the hwnd corresponding to a given pwnd 00374 * 00375 * 09-23-97 GerardoB Created. 00376 \***************************************************************************/ 00377 #if DBG 00378 void DBGValidateHW(PWND pwnd, HWND hwnd) 00379 { 00380 UserAssert((hwnd != NULL) ^ (pwnd == NULL)); 00381 if (hwnd != NULL) { 00382 UserAssert(pwnd == HMValidateCatHandleNoSecure(hwnd, TYPE_WINDOW)); 00383 } 00384 } 00385 void DBGValidateHWCCX(PWND ccxPwnd, HWND hwnd, PCLIENTINFO ccxPci) 00386 { 00387 UserAssert((hwnd != NULL) ^ (ccxPwnd == NULL)); 00388 if (hwnd != NULL) { 00389 UserAssert(ccxPwnd == HMValidateCatHandleNoSecureCCX(hwnd, TYPE_WINDOW, ccxPci)); 00390 } 00391 } 00392 HWND DBGHW (PWND pwnd) 00393 { 00394 HWND hwnd = _HW(pwnd); 00395 DBGValidateHW(pwnd, hwnd); 00396 return hwnd; 00397 } 00398 HWND DBGHWCCX (PWND ccxPwnd) 00399 { 00400 HWND hwnd = _HWCCX(ccxPwnd); 00401 PCLIENTINFO ccxPci = _GETPTI(ccxPwnd)->pClientInfo; 00402 if (KeIsAttachedProcess()) { 00403 UserAssert(KeGetCurrentThread()->ApcState.Process == &(_GETPTI(ccxPwnd)->ppi->Process->Pcb)); 00404 } else { 00405 UserAssert(PpiCurrent() == _GETPTI(ccxPwnd)->ppi); 00406 } 00407 DBGValidateHWCCX(ccxPwnd, hwnd, ccxPci); 00408 return hwnd; 00409 } 00410 HWND DBGHWq (PWND pwnd) 00411 { 00412 HWND hwnd; 00413 UserAssert(pwnd != NULL); 00414 hwnd = _HWq(pwnd); 00415 DBGValidateHW(pwnd, hwnd); 00416 return hwnd; 00417 } 00418 #endif 00419 /***************************************************************************\ 00420 * DBGHMValidateFreeLists 00421 * 00422 * Walks all handle free lists to make sure all links are fine. 00423 * 00424 * 10/08/97 GerardoB Created 00425 \***************************************************************************/ 00426 #if DBG 00427 void DBGHMValidateFreeList (ULONG_PTR iheFreeNext, BOOL fEven) 00428 { 00429 PHE phe; 00430 do { 00431 UserAssert(fEven ^ !!(iheFreeNext & 0x1)); 00432 UserAssert(iheFreeNext < gpsi->cHandleEntries); 00433 phe = &gSharedInfo.aheList[iheFreeNext]; 00434 UserAssert(phe->bType == TYPE_FREE); 00435 UserAssert(phe->pOwner == NULL); 00436 UserAssert(phe->bFlags == 0); 00437 iheFreeNext = (ULONG_PTR)phe->phead; 00438 } while (iheFreeNext != 0); 00439 } 00440 void DBGHMValidateFreeLists (void) 00441 { 00442 DWORD dw; 00443 PHANDLEPAGE php = gpHandlePages; 00444 00445 for (dw = 0; dw < gcHandlePages; ++dw, ++php) { 00446 if (php->iheFreeEven != 0) { 00447 DBGHMValidateFreeList(php->iheFreeEven, TRUE); 00448 } 00449 if (php->iheFreeOdd != 0) { 00450 DBGHMValidateFreeList(php->iheFreeOdd, FALSE); 00451 } 00452 } /* for */ 00453 } 00454 #else 00455 #define DBGHMValidateFreeLists() 00456 #endif 00457 00458 #if DBG 00459 00460 /***************************************************************************\ 00461 * DbgDumpHandleTable 00462 * 00463 \***************************************************************************/ 00464 DWORD DbgDumpHandleTable( 00465 VOID) 00466 { 00467 DWORD dw; 00468 PHE phe; 00469 DWORD dwHandles = 0; 00470 00471 phe = gSharedInfo.aheList; 00472 00473 if (phe == NULL) { 00474 KdPrint(("\nTERMSRV\nEmpty handle table\n")); 00475 return 0; 00476 } 00477 00478 KdPrint(("\nTERMSRV\nDump the handle table\n")); 00479 KdPrint(("---------------------------------------------------\n")); 00480 KdPrint((" phead handle lock pOwner type flags\n")); 00481 KdPrint(("---------------------------------------------------\n")); 00482 00483 for (dw = 0; dw <= giheLast; dw++, phe++) { 00484 if (phe->bType == TYPE_FREE) { 00485 UserAssert(phe->pOwner == NULL); 00486 continue; 00487 } 00488 00489 KdPrint(("%04d %08x %08x %08d %08x %04x %05x\n", 00490 dwHandles++, 00491 phe->phead, 00492 phe->phead->h, 00493 phe->phead->cLockObj, 00494 phe->pOwner, 00495 phe->bType, 00496 phe->bFlags)); 00497 } 00498 00499 KdPrint(("----------------------------------------------\n")); 00500 KdPrint(("Number of handles left: %d\n", dwHandles)); 00501 KdPrint(("End of handle table\n")); 00502 00503 UserAssert(dwHandles == 0); 00504 00505 return dwHandles; 00506 } 00507 00508 /***************************************************************************\ 00509 * HMCleanUpHandleTable 00510 * 00511 \***************************************************************************/ 00512 VOID HMCleanUpHandleTable( 00513 VOID) 00514 { 00515 DbgDumpHandleTable(); 00516 00517 if (LockRecordLookaside != NULL) { 00518 ExDeletePagedLookasideList(LockRecordLookaside); 00519 UserFreePool(LockRecordLookaside); 00520 } 00521 } 00522 #endif // DBG 00523 00524 /***************************************************************************\ 00525 * HMInitHandleEntries 00526 * 00527 * 10/10/97 GerardoB Extracted from HMInitHandleTable and HMGrowHandleTable 00528 \***************************************************************************/ 00529 void HMInitHandleEntries (ULONG_PTR iheFirstFree) 00530 { 00531 ULONG_PTR ihe; 00532 PHE pheT; 00533 /* 00534 * Zero out all the new entries 00535 */ 00536 RtlZeroMemory (&gSharedInfo.aheList[iheFirstFree], 00537 (gpsi->cHandleEntries - iheFirstFree) * sizeof(HANDLEENTRY)); 00538 /* 00539 * Link them together. 00540 * Each free odd/even entry points to the next odd/even free entry. 00541 */ 00542 ihe = iheFirstFree; 00543 for (pheT = &gSharedInfo.aheList[ihe]; ihe < gpsi->cHandleEntries; ihe++, pheT++) { 00544 pheT->phead = (PHEAD)(ihe + 2); 00545 /* pheT->bType = TYPE_FREE; */ 00546 pheT->wUniq = 1; 00547 } 00548 /* 00549 * Terminate the lists. 00550 */ 00551 if (gpsi->cHandleEntries > iheFirstFree) { 00552 UserAssert(pheT - 1 >= &gSharedInfo.aheList[iheFirstFree]); 00553 (pheT - 1)->phead = NULL; 00554 } 00555 if (gpsi->cHandleEntries > iheFirstFree + 1) { 00556 UserAssert(pheT - 2 >= &gSharedInfo.aheList[iheFirstFree]); 00557 (pheT - 2)->phead = NULL; 00558 } 00559 /* 00560 * Let's check that we got it right 00561 */ 00562 DBGHMValidateFreeLists(); 00563 } 00564 /***************************************************************************\ 00565 * HMInitHandleTable 00566 * 00567 * Initialize the handle table. Unused entries are linked together. 00568 * 00569 * 01-13-92 ScottLu Created. 00570 \***************************************************************************/ 00571 00572 #define CHANDLEENTRIESINIT 200 00573 #define CLOCKENTRIESINIT 100 00574 00575 BOOL HMInitHandleTable( 00576 PVOID pReadOnlySharedSectionBase) 00577 { 00578 NTSTATUS Status; 00579 SIZE_T ulCommit; 00580 00581 /* 00582 * Allocate the handle page array. Make it big enough 00583 * for 4 pages, which should be sufficient for nearly 00584 * all instances. 00585 */ 00586 gpHandlePages = UserAllocPool( 00587 CPAGEENTRIESINIT * sizeof(HANDLEPAGE), TAG_SYSTEM); 00588 00589 if (gpHandlePages == NULL) 00590 return FALSE; 00591 00592 #if DBG 00593 if (!NT_SUCCESS(InitLockRecordLookaside())) 00594 return FALSE; 00595 #endif 00596 00597 /* 00598 * Allocate the array. We have the space from 00599 * NtCurrentPeb()->ReadOnlySharedMemoryBase to 00600 * NtCurrentPeb()->ReadOnlySharedMemoryHeap reserved for 00601 * the handle table. All we need to do is commit the pages. 00602 * 00603 * Compute the minimum size of the table. The allocation will 00604 * round this up to the next page size. 00605 */ 00606 ulCommit = gpsi->cbHandleTable = PAGE_SIZE; 00607 Status = CommitReadOnlyMemory(ghSectionShared, &ulCommit, 0, NULL); 00608 00609 if (!NT_SUCCESS(Status)) 00610 return FALSE; 00611 00612 gSharedInfo.aheList = pReadOnlySharedSectionBase; 00613 gpsi->cHandleEntries = gpsi->cbHandleTable / sizeof(HANDLEENTRY); 00614 gcHandlePages = 1; 00615 00616 /* 00617 * Initialize the handlepage info. Handle 0 is reserved so even free list 00618 * starts at 2. 00619 */ 00620 gpHandlePages[0].iheFreeOdd = 1; 00621 gpHandlePages[0].iheFreeEven = 2; 00622 gpHandlePages[0].iheLimit = gpsi->cHandleEntries; 00623 /* 00624 * Initialize the handle entries. 00625 */ 00626 HMInitHandleEntries(0); 00627 /* 00628 * PW(NULL) (ie, handle 0) must map to a NULL pointer. 00629 * Old comment: 00630 * Reserve the first handle table entry so that PW(NULL) maps to a 00631 * NULL pointer. Set it to TYPE_FREE so the cleanup code doesn't think 00632 * it is allocated. Set wUniq to 1 so that RevalidateHandles on NULL 00633 * will fail. 00634 */ 00635 gSharedInfo.aheList[0].phead = NULL; 00636 UserAssert(gSharedInfo.aheList[0].bType == TYPE_FREE); 00637 UserAssert(gSharedInfo.aheList[0].wUniq == 1); 00638 00639 #if DBG 00640 /* 00641 * Make sure we don't need to add the special case to handle HMINDEXBITS in this function. 00642 */ 00643 UserAssert(gpsi->cHandleEntries <= HMINDEXBITS); 00644 /* 00645 * PDESKOBJHEAD won't do the right casting unless these structs have 00646 * the same size. 00647 */ 00648 UserAssert(sizeof(THROBJHEAD) == sizeof(PROCOBJHEAD)); 00649 UserAssert(sizeof(THRDESKHEAD) == sizeof(PROCDESKHEAD)); 00650 UserAssert(sizeof(THRDESKHEAD) == sizeof(DESKOBJHEAD)); 00651 /* 00652 * Validate type flags to make sure that assumptions made 00653 * throughout HM code are OK. 00654 */ 00655 { 00656 HANDLETYPEINFO * pahti = (HANDLETYPEINFO *) gahti; 00657 UINT uTypes = TYPE_CTYPES; 00658 BYTE bObjectCreateFlags; 00659 while (uTypes-- != 0) { 00660 bObjectCreateFlags = pahti->bObjectCreateFlags; 00661 /* 00662 * Illegal flag combinations 00663 */ 00664 UserAssert(!((bObjectCreateFlags & OCF_DESKTOPHEAP) && (bObjectCreateFlags & OCF_MARKPROCESS))); 00665 /* 00666 * Pointless (and probably illegal) flag combinations 00667 */ 00668 UserAssert(!((bObjectCreateFlags & OCF_DESKTOPHEAP) && (bObjectCreateFlags & OCF_SHAREDHEAP))); 00669 UserAssert(!((bObjectCreateFlags & OCF_USEPOOLQUOTA) && (bObjectCreateFlags & OCF_SHAREDHEAP))); 00670 UserAssert(!((bObjectCreateFlags & OCF_THREADOWNED) && (bObjectCreateFlags & OCF_PROCESSOWNED))); 00671 UserAssert(!(bObjectCreateFlags & OCF_USEPOOLQUOTA) 00672 || !(bObjectCreateFlags & OCF_DESKTOPHEAP) 00673 || (bObjectCreateFlags & OCF_USEPOOLIFNODESKTOP)); 00674 00675 /* 00676 * Required flag combinations 00677 */ 00678 UserAssert(!(bObjectCreateFlags & OCF_DESKTOPHEAP) 00679 || (bObjectCreateFlags & (OCF_PROCESSOWNED | OCF_THREADOWNED))); 00680 00681 UserAssert(!(bObjectCreateFlags & OCF_MARKPROCESS) 00682 || (bObjectCreateFlags & OCF_PROCESSOWNED)); 00683 00684 UserAssert(!(bObjectCreateFlags & OCF_USEPOOLIFNODESKTOP) 00685 || (bObjectCreateFlags & OCF_DESKTOPHEAP)); 00686 00687 00688 pahti++; 00689 } /* while (uTypes-- != 0) */ 00690 } 00691 #endif 00692 00693 return TRUE; 00694 } 00695 00696 /***************************************************************************\ 00697 * HMGrowHandleTable 00698 * 00699 * Grows the handle table. Assumes the handle table already exists. 00700 * 00701 * 01-13-92 ScottLu Created. 00702 \***************************************************************************/ 00703 00704 BOOL HMGrowHandleTable() 00705 { 00706 ULONG_PTR i, iheFirstFree; 00707 PHE pheT; 00708 PVOID p; 00709 PHANDLEPAGE phpNew; 00710 DWORD dwCommitOffset; 00711 SIZE_T ulCommit; 00712 NTSTATUS Status; 00713 00714 /* 00715 * If we've run out of handle space, fail. 00716 */ 00717 i = gpsi->cHandleEntries; 00718 if (i & ~HMINDEXBITS) 00719 return FALSE; 00720 00721 /* 00722 * Grow the page table if need be. 00723 */ 00724 i = gcHandlePages + 1; 00725 if (i > CPAGEENTRIESINIT) { 00726 DWORD dwSize = gcHandlePages * sizeof(HANDLEPAGE); 00727 00728 phpNew = UserReAllocPool( 00729 gpHandlePages, dwSize, dwSize + sizeof(HANDLEPAGE), TAG_SYSTEM); 00730 00731 if (phpNew == NULL) 00732 return FALSE; 00733 00734 gpHandlePages = phpNew; 00735 } 00736 00737 /* 00738 * Commit some more pages to the table. First find the 00739 * address where the commitment needs to be. 00740 */ 00741 p = (PBYTE)gSharedInfo.aheList + gpsi->cbHandleTable; 00742 00743 if (p >= Win32HeapGetHandle(gpvSharedAlloc)) { 00744 return FALSE; 00745 } 00746 00747 dwCommitOffset = (ULONG)((PBYTE)p - (PBYTE)gpvSharedBase); 00748 00749 ulCommit = PAGE_SIZE; 00750 00751 Status = CommitReadOnlyMemory(ghSectionShared, &ulCommit, dwCommitOffset, NULL); 00752 00753 if (!NT_SUCCESS(Status)) 00754 return FALSE; 00755 00756 phpNew = &gpHandlePages[gcHandlePages++]; 00757 00758 /* 00759 * Update the global information to include the new 00760 * page. 00761 */ 00762 iheFirstFree = gpsi->cHandleEntries; 00763 if (gpsi->cHandleEntries & 0x1) { 00764 phpNew->iheFreeOdd = gpsi->cHandleEntries; 00765 phpNew->iheFreeEven = gpsi->cHandleEntries + 1; 00766 } else { 00767 phpNew->iheFreeEven = gpsi->cHandleEntries; 00768 phpNew->iheFreeOdd = gpsi->cHandleEntries + 1; 00769 } 00770 gpsi->cbHandleTable += PAGE_SIZE; 00771 00772 /* 00773 * Check for handle overflow 00774 */ 00775 gpsi->cHandleEntries = gpsi->cbHandleTable / sizeof(HANDLEENTRY); 00776 if (gpsi->cHandleEntries & ~HMINDEXBITS) { 00777 gpsi->cHandleEntries = (HMINDEXBITS + 1); 00778 } 00779 00780 phpNew->iheLimit = gpsi->cHandleEntries; 00781 if (phpNew->iheFreeEven >= phpNew->iheLimit) { 00782 phpNew->iheFreeEven = 0; 00783 } 00784 if (phpNew->iheFreeOdd >= phpNew->iheLimit) { 00785 phpNew->iheFreeOdd = 0; 00786 } 00787 00788 HMInitHandleEntries(iheFirstFree); 00789 00790 /* 00791 * HMINDEXBITS has a special meaning. We used to handle this in HMAllocObject. 00792 * Now we handle it here right after adding that handle to the table. 00793 * Old Comment: 00794 * Reserve this table entry so that PW(HMINDEXBITS) maps to a 00795 * NULL pointer. Set it to TYPE_FREE so the cleanup code doesn't think 00796 * it is allocated. Set wUniq to 1 so that RevalidateHandles on HMINDEXBITS 00797 * will fail. 00798 */ 00799 if ((gpsi->cHandleEntries > HMINDEXBITS) 00800 && (phpNew->iheFreeOdd != 0) 00801 && (phpNew->iheFreeOdd <= HMINDEXBITS)) { 00802 00803 pheT = &gSharedInfo.aheList[HMINDEXBITS]; 00804 if (phpNew->iheFreeOdd == HMINDEXBITS) { 00805 phpNew->iheFreeOdd = (ULONG_PTR)pheT->phead; 00806 } else { 00807 UserAssert(pheT - 2 >= &gSharedInfo.aheList[iheFirstFree]); 00808 UserAssert((pheT - 2)->phead == (PVOID)HMINDEXBITS); 00809 (pheT - 2)->phead = pheT->phead; 00810 } 00811 pheT->phead = NULL; 00812 UserAssert(pheT->bType == TYPE_FREE); 00813 UserAssert(pheT->wUniq == 1); 00814 } 00815 00816 return TRUE; 00817 } 00818 00819 /***************************************************************************\ 00820 * HMAllocObject 00821 * 00822 * Allocs a non-secure object by allocating a handle and memory for 00823 * the object. 00824 * 00825 * 01-13-92 ScottLu Created. 00826 \***************************************************************************/ 00827 00828 PVOID HMAllocObject( 00829 PTHREADINFO ptiOwner, 00830 PDESKTOP pdeskSrc, 00831 BYTE bType, 00832 DWORD size) 00833 { 00834 DWORD i; 00835 PHEAD phead; 00836 PHE pheT; 00837 ULONG_PTR iheFree, *piheFreeHead; 00838 PHANDLEPAGE php; 00839 BYTE bCreateFlags; 00840 PPROCESSINFO ppiQuotaCharge = NULL; 00841 BOOL fUsePoolIfNoDesktop; 00842 BOOL fEven; 00843 00844 CheckCritIn(); 00845 bCreateFlags = gahti[bType].bObjectCreateFlags; 00846 00847 #if DBG 00848 /* 00849 * Validate size 00850 */ 00851 if (bCreateFlags & OCF_VARIABLESIZE) { 00852 UserAssert(gahti[bType].uSize <= size); 00853 } else { 00854 UserAssert(gahti[bType].uSize == size); 00855 } 00856 #endif 00857 00858 /* 00859 * Check for process handle quota 00860 */ 00861 if (bCreateFlags & (OCF_PROCESSOWNED | OCF_THREADOWNED)) { 00862 UserAssert(ptiOwner != NULL); 00863 ppiQuotaCharge = ptiOwner->ppi; 00864 if (ppiQuotaCharge->UserHandleCount >= gUserProcessHandleQuota) { 00865 RIPERR0(ERROR_NO_MORE_USER_HANDLES, 00866 RIP_WARNING, 00867 "USER: HMAllocObject: out of handle quota\n"); 00868 return NULL; 00869 } 00870 } 00871 00872 /* 00873 * Find the next free handle 00874 * Window handles must be even; hence we try first to use odd handles 00875 * for all other objects. 00876 * Old comment: 00877 * Some wow apps, like WinProj, require even Window handles so we'll 00878 * accomodate them; build a list of the odd handles so they won't get lost 00879 * 10/13/97: WinProj never fixed this; even the 32 bit version has the problem. 00880 */ 00881 fEven = (bType == TYPE_WINDOW); 00882 piheFreeHead = NULL; 00883 do { 00884 php = gpHandlePages; 00885 for (i = 0; i < gcHandlePages; ++i, ++php) { 00886 if (fEven) { 00887 if (php->iheFreeEven != 0) { 00888 piheFreeHead = &php->iheFreeEven; 00889 break; 00890 } 00891 } else { 00892 if (php->iheFreeOdd != 0) { 00893 piheFreeHead = &php->iheFreeOdd; 00894 break; 00895 } 00896 } 00897 } /* for */ 00898 /* 00899 * If we couldn't find an odd handle, then search for an even one 00900 */ 00901 fEven = ((piheFreeHead == NULL) && !fEven); 00902 } while (fEven); 00903 /* 00904 * If there are no free handles we can use, grow the table 00905 */ 00906 if (piheFreeHead == NULL) { 00907 HMGrowHandleTable(); 00908 /* 00909 * If the table didn't grow, get out. 00910 */ 00911 if (i == gcHandlePages) { 00912 RIPMSG0(RIP_WARNING, "HMAllocObject: could not grow handle space"); 00913 return NULL; 00914 } 00915 /* 00916 * Because the handle page table may have moved, 00917 * recalc the page entry pointer. 00918 */ 00919 php = &gpHandlePages[i]; 00920 piheFreeHead = (bType == TYPE_WINDOW ? &php->iheFreeEven : &php->iheFreeOdd); 00921 if (*piheFreeHead == 0) { 00922 UserAssert(gpsi->cHandleEntries == (HMINDEXBITS + 1)); 00923 RIPMSG0(RIP_WARNING, "HMAllocObject: handle table is full"); 00924 return NULL; 00925 } 00926 } 00927 /* 00928 * HMINDEXBITS is a reserved value that should never be in the free lists 00929 * (see HMGrowHandleTable()); 00930 */ 00931 UserAssert(HMIndexFromHandle(*piheFreeHead) != HMINDEXBITS); 00932 /* 00933 * Try to allocate the object. If this fails, bail out. 00934 */ 00935 if ((bCreateFlags & OCF_DESKTOPHEAP) && pdeskSrc) { 00936 phead = (PHEAD)DesktopAlloc(pdeskSrc, size, DTAG_HANDTABL); 00937 if (phead) { 00938 LockDesktop(&((PDESKOBJHEAD)phead)->rpdesk, pdeskSrc, LDL_OBJ_DESK, (ULONG_PTR)phead); 00939 ((PDESKOBJHEAD)phead)->pSelf = (PBYTE)phead; 00940 } 00941 } else if (bCreateFlags & OCF_SHAREDHEAP) { 00942 UserAssert(!pdeskSrc); 00943 phead = (PHEAD)SharedAlloc(size); 00944 } else { 00945 fUsePoolIfNoDesktop = !pdeskSrc && (bCreateFlags & OCF_USEPOOLIFNODESKTOP); 00946 UserAssert(!(bCreateFlags & OCF_DESKTOPHEAP) || fUsePoolIfNoDesktop); 00947 00948 if ((bCreateFlags & OCF_USEPOOLQUOTA) && !fUsePoolIfNoDesktop) { 00949 phead = (PHEAD)UserAllocPoolWithQuotaZInit(size, gahti[bType].dwAllocTag); 00950 } else { 00951 phead = (PHEAD)UserAllocPoolZInit(size, gahti[bType].dwAllocTag); 00952 } 00953 } 00954 00955 if (phead == NULL) { 00956 RIPERR0(ERROR_NOT_ENOUGH_MEMORY, 00957 RIP_WARNING, 00958 "USER: HMAllocObject: out of memory"); 00959 return NULL; 00960 } 00961 /* 00962 * We're going to use this handle so get it off its free list. 00963 * The free handle phead points to the next free handle. 00964 */ 00965 iheFree = *piheFreeHead; 00966 pheT = &gSharedInfo.aheList[iheFree]; 00967 *piheFreeHead = (ULONG_PTR)pheT->phead; 00968 DBGHMValidateFreeLists(); 00969 /* 00970 * Track high water mark for handle allocation. 00971 */ 00972 if ((DWORD)iheFree > giheLast) { 00973 giheLast = (DWORD)iheFree; 00974 } 00975 /* 00976 * Setup the handle contents, plus initialize the object header. 00977 */ 00978 pheT->bType = bType; 00979 pheT->phead = phead; 00980 UserAssert(pheT->bFlags == 0); 00981 if (bCreateFlags & OCF_PROCESSOWNED) { 00982 if ((ptiOwner->TIF_flags & TIF_16BIT) && (ptiOwner->ptdb)) { 00983 ((PPROCOBJHEAD)phead)->hTaskWow = ptiOwner->ptdb->hTaskWow; 00984 } else { 00985 ((PPROCOBJHEAD)phead)->hTaskWow = 0; 00986 } 00987 pheT->pOwner = ptiOwner->ppi; 00988 if (bCreateFlags & OCF_MARKPROCESS) { 00989 ((PPROCMARKHEAD)phead)->ppi = ptiOwner->ppi; 00990 } 00991 } else if (bCreateFlags & OCF_THREADOWNED) { 00992 ((PTHROBJHEAD)phead)->pti = pheT->pOwner = ptiOwner; 00993 } else { 00994 /* 00995 * The caller is wasting time if ptiOwner != NULL 00996 * The handle entry must already have pOwner == NULL. 00997 */ 00998 UserAssert(ptiOwner == NULL); 00999 UserAssert(pheT->pOwner == NULL); 01000 } 01001 01002 phead->h = HMHandleFromIndex(iheFree); 01003 01004 if (ppiQuotaCharge) { 01005 ppiQuotaCharge->UserHandleCount++; 01006 DBGValidateHandleQuota(); 01007 } 01008 01009 #if DBG 01010 /* 01011 * performance counter dumphmgr 01012 * dwPrevCount is used for the snapshot option 01013 */ 01014 01015 gaPerfhti[bType].lTotalCount++; 01016 gaPerfhti[bType].lCount++; 01017 if (gaPerfhti[bType].lCount > gaPerfhti[bType].lMaxCount) { 01018 gaPerfhti[bType].lMaxCount = gaPerfhti[bType].lCount; 01019 } 01020 if ((bCreateFlags & OCF_DESKTOPHEAP) && (pdeskSrc != NULL)) { 01021 gaPerfhti[bType].lSize += RtlSizeHeap(Win32HeapGetHandle(pdeskSrc->pheapDesktop), 0, phead); 01022 } else if (bCreateFlags & OCF_SHAREDHEAP) { 01023 gaPerfhti[bType].lSize += RtlSizeHeap(Win32HeapGetHandle(gpvSharedAlloc), 0, phead); 01024 } else { 01025 unsigned char notUsed; 01026 gaPerfhti[bType].lSize += ExQueryPoolBlockSize(phead, &notUsed); 01027 } 01028 01029 #endif // DBG 01030 01031 /* 01032 * Return a handle entry pointer. 01033 */ 01034 return pheT->phead; 01035 } 01036 01037 01038 01039 #if 0 01040 #define HANDLEF_FREECHECK 0x80 01041 VOID CheckHMTable( 01042 PVOID pobj) 01043 { 01044 PHE pheT, pheMax; 01045 01046 if (giheLast) { 01047 pheMax = &gSharedInfo.aheList[giheLast]; 01048 for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) { 01049 if (pheT->bType == TYPE_FREE) { 01050 continue; 01051 } 01052 if (pheT->phead == pobj && !(pheT->bFlags & HANDLEF_FREECHECK)) { 01053 UserAssert(FALSE); 01054 } 01055 } 01056 } 01057 } 01058 #endif 01059 01060 01061 /***************************************************************************\ 01062 * HMFreeObject 01063 * 01064 * Frees an object - the handle and the referenced memory. 01065 * 01066 * 01-13-92 ScottLu Created. 01067 \***************************************************************************/ 01068 01069 BOOL HMFreeObject( 01070 PVOID pobj) 01071 { 01072 PHE pheT; 01073 WORD wUniqT; 01074 PHANDLEPAGE php; 01075 DWORD i; 01076 ULONG_PTR iheCurrent, *piheCurrentHead; 01077 BYTE bCreateFlags; 01078 PDESKTOP pdesk; 01079 PPROCESSINFO ppiQuotaCharge = NULL; 01080 #if DBG 01081 PLR plrT, plrNextT; 01082 unsigned char notUsed; 01083 #endif 01084 01085 UserAssert(((PHEAD)pobj)->cLockObj == 0); 01086 UserAssert(pobj == HtoPqCat(PtoHq(pobj))); 01087 /* 01088 * Free the object first. 01089 */ 01090 pheT = HMPheFromObject(pobj); 01091 bCreateFlags = gahti[pheT->bType].bObjectCreateFlags; 01092 01093 UserAssertMsg1(pheT->bType != TYPE_FREE, 01094 "Object already marked as freed!!! %#p", pobj); 01095 01096 /* 01097 * decr process handle use 01098 */ 01099 if (bCreateFlags & OCF_PROCESSOWNED) { 01100 ppiQuotaCharge = (PPROCESSINFO)pheT->pOwner; 01101 UserAssert(ppiQuotaCharge != NULL); 01102 } else if (bCreateFlags & OCF_THREADOWNED) { 01103 ppiQuotaCharge = (PPROCESSINFO)(((PTHREADINFO)(pheT->pOwner))->ppi); 01104 UserAssert(ppiQuotaCharge != NULL); 01105 } else { 01106 ppiQuotaCharge = NULL; 01107 } 01108 01109 if (ppiQuotaCharge != NULL) { 01110 ppiQuotaCharge->UserHandleCount--; 01111 } 01112 01113 if (pheT->bFlags & HANDLEF_GRANTED) { 01114 HMCleanupGrantedHandle(pheT->phead->h); 01115 pheT->bFlags &= ~HANDLEF_GRANTED; 01116 } 01117 01118 #if DBG 01119 /* 01120 * performance counters 01121 */ 01122 gaPerfhti[pheT->bType].lCount--; 01123 01124 if ((bCreateFlags & OCF_DESKTOPHEAP) && ((PDESKOBJHEAD)pobj)->rpdesk) { 01125 pdesk = ((PDESKOBJHEAD)pobj)->rpdesk; 01126 gaPerfhti[pheT->bType].lSize -= RtlSizeHeap(Win32HeapGetHandle(pdesk->pheapDesktop), 0, pobj); 01127 } else if (bCreateFlags & OCF_SHAREDHEAP) { 01128 gaPerfhti[pheT->bType].lSize -= RtlSizeHeap(Win32HeapGetHandle(gpvSharedAlloc), 0, pobj); 01129 } else { 01130 gaPerfhti[pheT->bType].lSize -= ExQueryPoolBlockSize(pobj, &notUsed); 01131 } 01132 01133 #endif // DBG 01134 01135 if ((bCreateFlags & OCF_DESKTOPHEAP)) { 01136 #if DBG 01137 BOOL bSuccess; 01138 #endif 01139 UserAssert(((PDESKOBJHEAD)pobj)->rpdesk != NULL); 01140 01141 pdesk = ((PDESKOBJHEAD)pobj)->rpdesk; 01142 UnlockDesktop(&((PDESKOBJHEAD)pobj)->rpdesk, LDU_OBJ_DESK, (ULONG_PTR)pobj); 01143 01144 if (pheT->bFlags & HANDLEF_POOL) { 01145 UserFreePool(pobj); 01146 } else { 01147 01148 #if DBG 01149 bSuccess = 01150 #endif 01151 DesktopFree(pdesk, pobj); 01152 #if DBG 01153 if (!bSuccess) { 01154 /* 01155 * We would hit this assert in HYDRA trying to free the 01156 * mother desktop window which was allocated out of pool 01157 */ 01158 RIPMSG1(RIP_ERROR, "Object already freed from desktop heap! %#p", pobj); 01159 } 01160 #endif 01161 } 01162 01163 } else if (bCreateFlags & OCF_SHAREDHEAP) { 01164 SharedFree(pobj); 01165 } else { 01166 UserFreePool(pobj); 01167 } 01168 01169 #if DBG 01170 /* 01171 * Go through and delete the lock records, if they exist. 01172 */ 01173 for (plrT = pheT->plr; plrT != NULL; plrT = plrNextT) { 01174 01175 /* 01176 * Remember the next one before freeing this one. 01177 */ 01178 plrNextT = plrT->plrNext; 01179 FreeLockRecord((HANDLE)plrT); 01180 } 01181 #endif 01182 01183 /* 01184 * Clear the handle contents. Need to remember the uniqueness across 01185 * the clear. Also, advance uniqueness on free so that uniqueness checking 01186 * against old handles also fails. 01187 */ 01188 wUniqT = (WORD)((pheT->wUniq + 1) & HMUNIQBITS); 01189 RtlZeroMemory(pheT, sizeof(HANDLEENTRY)); 01190 pheT->wUniq = wUniqT; 01191 01192 /* 01193 * Change the handle type to TYPE_FREE so we know what type this handle 01194 * is. (TYPE_FREE is defined as zero) 01195 */ 01196 /* pheT->bType = TYPE_FREE; */ 01197 UserAssert(pheT->bType == TYPE_FREE); 01198 01199 /* 01200 * Put the handle on the free list of the appropriate page. 01201 */ 01202 php = gpHandlePages; 01203 iheCurrent = pheT - gSharedInfo.aheList; 01204 for (i = 0; i < gcHandlePages; ++i, ++php) { 01205 if (iheCurrent < php->iheLimit) { 01206 piheCurrentHead = (iheCurrent & 0x1 ? &php->iheFreeOdd : &php->iheFreeEven); 01207 pheT->phead = (PHEAD)*piheCurrentHead; 01208 *piheCurrentHead = iheCurrent; 01209 DBGHMValidateFreeLists(); 01210 break; 01211 } 01212 } 01213 /* 01214 * We must have found it. 01215 */ 01216 UserAssert(i < gcHandlePages); 01217 01218 UserAssert(pheT->pOwner == NULL); 01219 01220 DBGValidateHandleQuota(); 01221 01222 return TRUE; 01223 } 01224 01225 01226 /***************************************************************************\ 01227 * HMMarkObjectDestroy 01228 * 01229 * Marks an object for destruction. 01230 * 01231 * Returns TRUE if the object can be destroyed; that is, if it's 01232 * lock count is 0. 01233 * 01234 * 02-10-92 ScottLu Created. 01235 \***************************************************************************/ 01236 01237 BOOL HMMarkObjectDestroy( 01238 PVOID pobj) 01239 { 01240 PHE phe; 01241 01242 phe = HMPheFromObject(pobj); 01243 01244 #if DEBUGTAGS 01245 /* 01246 * Record where the object was marked for destruction. 01247 */ 01248 if (IsDbgTagEnabled(DBGTAG_TrackLocks)) { 01249 if (!(phe->bFlags & HANDLEF_DESTROY)) { 01250 HMRecordLock(LOCKRECORD_MARKDESTROY, pobj, ((PHEAD)pobj)->cLockObj); 01251 } 01252 } 01253 #endif 01254 01255 /* 01256 * Set the destroy flag so our unlock code will know we're trying to 01257 * destroy this object. 01258 */ 01259 phe->bFlags |= HANDLEF_DESTROY; 01260 01261 /* 01262 * If this object can't be destroyed, then CLEAR the HANDLEF_INDESTROY 01263 * flag - because this object won't be currently "in destruction"! 01264 * (if we didn't clear it, when it was unlocked it wouldn't get destroyed). 01265 */ 01266 if (((PHEAD)pobj)->cLockObj != 0) { 01267 phe->bFlags &= ~HANDLEF_INDESTROY; 01268 01269 /* 01270 * Return FALSE because we can't destroy this object. 01271 */ 01272 return FALSE; 01273 } 01274 01275 #if DBG 01276 /* 01277 * Ensure that this function only returns TRUE once. 01278 */ 01279 UserAssert(!(phe->bFlags & HANDLEF_MARKED_OK)); 01280 phe->bFlags |= HANDLEF_MARKED_OK; 01281 #endif 01282 01283 /* 01284 * Return TRUE because Lock count is zero - ok to destroy this object. 01285 */ 01286 return TRUE; 01287 } 01288 01289 01290 /***************************************************************************\ 01291 * HMDestroyObject 01292 * 01293 * This routine marks an object for destruction, and frees it if 01294 * it is unlocked. 01295 * 01296 * 10-13-94 JimA Created. 01297 \***************************************************************************/ 01298 01299 BOOL HMDestroyObject( 01300 PVOID pobj) 01301 { 01302 /* 01303 * First mark the object for destruction. This tells the locking code 01304 * that we want to destroy this object when the lock count goes to 0. 01305 * If this returns FALSE, we can't destroy the object yet (and can't get 01306 * rid of security yet either.) 01307 */ 01308 01309 if (!HMMarkObjectDestroy(pobj)) 01310 return FALSE; 01311 01312 /* 01313 * Ok to destroy... Free the handle (which will free the object 01314 * and the handle). 01315 */ 01316 HMFreeObject(pobj); 01317 return TRUE; 01318 } 01319 01320 #if DBG 01321 01322 NTSTATUS 01323 InitLockRecordLookaside() 01324 { 01325 LockRecordLookaside = UserAllocPoolNonPaged(sizeof(PAGED_LOOKASIDE_LIST), 01326 TAG_LOOKASIDE); 01327 if (LockRecordLookaside == NULL) { 01328 return STATUS_NO_MEMORY; 01329 } 01330 01331 ExInitializePagedLookasideList(LockRecordLookaside, 01332 NULL, 01333 NULL, 01334 SESSION_POOL_MASK, 01335 sizeof(LOCKRECORD), 01336 TAG_LOCKRECORD, 01337 1000); 01338 return STATUS_SUCCESS; 01339 } 01340 01341 PLR AllocLockRecord() 01342 { 01343 PLR plr; 01344 01345 /* 01346 * Allocate a LOCKRECORD structure. 01347 */ 01348 if ((plr = ExAllocateFromPagedLookasideList(LockRecordLookaside)) == NULL) { 01349 return NULL; 01350 } 01351 01352 RtlZeroMemory(plr, sizeof(*plr)); 01353 01354 return plr; 01355 } 01356 01357 01358 void FreeLockRecord( 01359 PLR plr) 01360 { 01361 ExFreeToPagedLookasideList(LockRecordLookaside, plr); 01362 } 01363 01364 01365 /***************************************************************************\ 01366 * HMRecordLock 01367 * 01368 * This routine records a lock on a "lock list", so that locks and unlocks 01369 * can be tracked in the debugger. Only called if DBGTAG_TrackLocks is enabled. 01370 * 01371 * 02-27-92 ScottLu Created. 01372 \***************************************************************************/ 01373 void HMRecordLock( 01374 PVOID ppobj, 01375 PVOID pobj, 01376 DWORD cLockObj) 01377 { 01378 PHE phe; 01379 PLR plr; 01380 int i; 01381 ULONG hash; 01382 01383 phe = HMPheFromObject(pobj); 01384 01385 if ((plr = AllocLockRecord()) == NULL) { 01386 RIPMSG0(RIP_ERROR, "HMRecordLock failed to allocate memory"); 01387 return; 01388 } 01389 01390 /* 01391 * Link it in front of the list 01392 */ 01393 plr->plrNext = phe->plr; 01394 phe->plr = plr; 01395 01396 /* 01397 * This propably happens only for unmatched locks 01398 */ 01399 if (((PHEAD)pobj)->cLockObj > cLockObj) { 01400 01401 RIPMSG3(RIP_WARNING, "Unmatched lock. ppobj %#p pobj %#p cLockObj %d", 01402 ppobj, pobj, cLockObj); 01403 01404 i = (int)cLockObj; 01405 i = -i; 01406 cLockObj = (DWORD)i; 01407 } 01408 01409 plr->ppobj = ppobj; 01410 plr->cLockObj = cLockObj; 01411 01412 GetStackTrace(1, 01413 LOCKRECORD_STACK, 01414 plr->trace, 01415 &hash); 01416 return; 01417 } 01418 #endif // DBG 01419 01420 01421 /***************************************************************************\ 01422 * HMLockObject 01423 * 01424 * This routine locks an object. This is a macro in retail systems. 01425 * 01426 * 02-24-92 ScottLu Created. 01427 \***************************************************************************/ 01428 01429 #if DBG 01430 void HMLockObject( 01431 PVOID pobj) 01432 { 01433 HANDLE h; 01434 PVOID pobjValidate; 01435 01436 /* 01437 * Validate by going through the handle entry so that we make sure pobj 01438 * is not just pointing off into space. This may GP fault, but that's 01439 * ok: this case should not ever happen if we're bug free. 01440 */ 01441 01442 h = HMPheFromObject(pobj)->phead->h; 01443 pobjValidate = HMRevalidateCatHandle(h); 01444 if (!pobj || pobj != pobjValidate) { 01445 RIPMSG2(RIP_ERROR, 01446 "HMLockObject invalid object %#p, handle %#p", 01447 pobj, h); 01448 return; 01449 } 01450 01451 /* 01452 * Inc the reference count. 01453 */ 01454 ((PHEAD)pobj)->cLockObj++; 01455 01456 if (((PHEAD)pobj)->cLockObj == 0) 01457 RIPMSG1(RIP_ERROR, "Object lock count has overflowed: %#p", pobj); 01458 } 01459 #endif // DBG 01460 01461 01462 /***************************************************************************\ 01463 * HMUnlockObjectInternal 01464 * 01465 * This routine is called from the macro HMUnlockObject when an object's 01466 * reference count drops to zero. This routine will destroy an object 01467 * if is has been marked for destruction. 01468 * 01469 * 01-21-92 ScottLu Created. 01470 \***************************************************************************/ 01471 01472 PVOID HMUnlockObjectInternal( 01473 PVOID pobj) 01474 { 01475 PHE phe; 01476 01477 /* 01478 * The object is not reference counted. If the object is not a zombie, 01479 * return success because the object is still around. 01480 */ 01481 phe = HMPheFromObject(pobj); 01482 if (!(phe->bFlags & HANDLEF_DESTROY)) 01483 return pobj; 01484 01485 /* 01486 * We're destroying the object based on an unlock... Make sure it isn't 01487 * currently being destroyed! (It is valid to have lock counts go from 01488 * 0 to != 0 to 0 during destruction... don't want recursion into 01489 * the destroy routine. 01490 */ 01491 if (phe->bFlags & HANDLEF_INDESTROY) 01492 return pobj; 01493 01494 HMDestroyUnlockedObject(phe); 01495 return NULL; 01496 } 01497 01498 01499 /***************************************************************************\ 01500 * HMAssignmentLock 01501 * 01502 * This api is used for structure and global variable assignment. 01503 * Returns pobjOld if the object was *not* destroyed. Means the object is 01504 * still valid. 01505 * 01506 * 02-24-92 ScottLu Created. 01507 \***************************************************************************/ 01508 01509 PVOID FASTCALL HMAssignmentLock( 01510 PVOID *ppobj, 01511 PVOID pobj) 01512 { 01513 PVOID pobjOld; 01514 01515 pobjOld = *ppobj; 01516 *ppobj = pobj; 01517 01518 /* 01519 * Unlocks the old, locks the new. 01520 */ 01521 if (pobjOld != NULL) { 01522 01523 /* 01524 * if we are locking in the same object that is there then 01525 * it is a no-op but we don't want to do the Unlock and the Lock 01526 * because the unlock could free object and the lock would lock 01527 * in a freed pointer; 6410. 01528 */ 01529 if (pobjOld == pobj) { 01530 return pobjOld; 01531 } 01532 01533 #if DEBUGTAGS 01534 01535 /* 01536 * Track assignment locks. 01537 */ 01538 if (IsDbgTagEnabled(DBGTAG_TrackLocks)) { 01539 if (!HMUnrecordLock(ppobj, pobjOld)) { 01540 HMRecordLock(ppobj, pobjOld, ((PHEAD)pobjOld)->cLockObj - 1); 01541 } 01542 } 01543 #endif 01544 01545 } 01546 01547 01548 if (pobj != NULL) { 01549 UserAssert(pobj == HMValidateCatHandleNoSecure(((PHEAD)pobj)->h, TYPE_GENERIC)); 01550 if (HMIsMarkDestroy(pobj)) { 01551 RIPERR2(ERROR_INVALID_PARAMETER, 01552 RIP_WARNING, 01553 "HMAssignmentLock, locking object %#p marked for destruction at %#p\n", 01554 pobj, ppobj); 01555 } 01556 #if DEBUGTAGS 01557 01558 /* 01559 * Track assignment locks. 01560 */ 01561 if (IsDbgTagEnabled(DBGTAG_TrackLocks)) { 01562 HMRecordLock(ppobj, pobj, ((PHEAD)pobj)->cLockObj + 1); 01563 if (HMIsMarkDestroy(pobj)) { 01564 01565 RIPMSG2(RIP_WARNING, 01566 "Locking object %#p marked for destruction at %#p", 01567 pobj, ppobj); 01568 } 01569 } 01570 #endif 01571 HMLockObject(pobj); 01572 } 01573 01574 /* 01575 * This unlock has been moved from up above, so that we implement a 01576 * "lock before unlock" strategy. Just in case pobjOld was the 01577 * only object referencing pobj, pobj won't go away when we unlock 01578 * pobjNew -- it will have been locked above. 01579 */ 01580 01581 if (pobjOld) { 01582 pobjOld = HMUnlockObject(pobjOld); 01583 } 01584 01585 return pobjOld; 01586 } 01587 01588 01589 /***************************************************************************\ 01590 * HMAssignmentLock 01591 * 01592 * This api is used for structure and global variable assignment. 01593 * Returns pobjOld if the object was *not* destroyed. Means the object is 01594 * still valid. 01595 * 01596 * 02-24-92 ScottLu Created. 01597 \***************************************************************************/ 01598 01599 PVOID FASTCALL HMAssignmentUnlock( 01600 PVOID *ppobj) 01601 { 01602 PVOID pobjOld; 01603 01604 pobjOld = *ppobj; 01605 *ppobj = NULL; 01606 01607 /* 01608 * Unlocks the old, locks the new. 01609 */ 01610 if (pobjOld != NULL) { 01611 01612 #if DEBUGTAGS 01613 01614 /* 01615 * Track assignment locks. 01616 */ 01617 if (IsDbgTagEnabled(DBGTAG_TrackLocks)) { 01618 if (!HMUnrecordLock(ppobj, pobjOld)) { 01619 HMRecordLock(ppobj, pobjOld, ((PHEAD)pobjOld)->cLockObj - 1); 01620 } 01621 } 01622 #endif 01623 pobjOld = HMUnlockObject(pobjOld); 01624 } 01625 01626 return pobjOld; 01627 } 01628 01629 01630 /***************************************************************************\ 01631 * IsValidThreadLock 01632 * 01633 * This routine checks to make sure that the thread lock structures passed 01634 * in are valid. 01635 * 01636 * 03-17-92 ScottLu Created. 01637 * 02-22-99 MCostea Also validate the shadow of the stack TL 01638 * from gThreadLocksArray 01639 \***************************************************************************/ 01640 #if DBG 01641 VOID IsValidThreadLock(PTHREADINFO pti, PTL ptl, ULONG_PTR dwLimit, BOOLEAN fHM) 01642 { 01643 /* 01644 * Check that ptl is a valid stack address 01645 * Allow (ULONG_PTR)ptl == dwLimit so we can call ValidateThreadLocks passing 01646 * the address of the last thing we locked. 01647 */ 01648 UserAssert((ULONG_PTR)ptl >= dwLimit); 01649 UserAssert((ULONG_PTR)ptl < (ULONG_PTR)KeGetCurrentThread()->StackBase); 01650 /* 01651 * Check ptl owner. 01652 */ 01653 UserAssert(ptl->pW32Thread == (PW32THREAD)pti); 01654 /* 01655 * If this is an HM object, verify handle and lock count (guess max value) 01656 */ 01657 if (fHM && (ptl->pobj != NULL)) { 01658 /* 01659 * The locked object could be a destroyed object. 01660 */ 01661 UserAssert(ptl->pobj == HtoPqCat(PtoHq(ptl->pobj))); 01662 if (((PHEAD)ptl->pobj)->cLockObj >= 32000) { 01663 RIPMSG2(RIP_WARNING, "IsValidThreadLock: Object %#p has %d locks", ptl->pobj, ((PHEAD)ptl->pobj)->cLockObj); 01664 } 01665 } 01666 /* 01667 * Make sure the shadow in gThreadLocksArray is doing fine 01668 */ 01669 UserAssert(ptl->ptl->ptl == ptl); 01670 } 01671 #endif 01672 01673 /***************************************************************************\ 01674 * ValidateThreadLocks 01675 * 01676 * This routine validates the thread lock list of a thread. 01677 * 01678 * 03-10-92 ScottLu Created. 01679 \***************************************************************************/ 01680 01681 #if DBG 01682 ULONG ValidateThreadLocks(PTL NewLock, PTL OldLock, ULONG_PTR dwLimit, BOOLEAN fHM) 01683 { 01684 UINT uTLCount = 0; 01685 PTL ptlTopLock = OldLock; 01686 PTHREADINFO ptiCurrent; 01687 01688 BEGIN_REENTERCRIT(); 01689 01690 ptiCurrent = PtiCurrent(); 01691 01692 /* 01693 * Validate the new thread lock. 01694 */ 01695 if (NewLock != NULL) { 01696 UserAssert(NewLock->next == OldLock); 01697 IsValidThreadLock(ptiCurrent, NewLock, dwLimit, fHM); 01698 uTLCount++; 01699 } 01700 01701 /* 01702 * Loop through the list of thread locks and check to make sure the 01703 * new lock is not in the list and that list is valid. 01704 */ 01705 while (OldLock != NULL) { 01706 /* 01707 * The new lock must not be the same as the old lock. 01708 */ 01709 UserAssert(NewLock != OldLock); 01710 /* 01711 * Validate the old thread lock. 01712 */ 01713 IsValidThreadLock(ptiCurrent, OldLock, dwLimit, fHM); 01714 uTLCount++; 01715 OldLock = OldLock->next; 01716 } 01717 /* 01718 * If this is thread lock, set uTLCount, else verify it 01719 */ 01720 if (NewLock != NULL) { 01721 NewLock->uTLCount = uTLCount; 01722 } else { 01723 if (ptlTopLock == NULL) { 01724 RIPMSG0(RIP_WARNING, "ptlTopLock is NULL, the system will AV now"); 01725 } 01726 UserAssert(uTLCount == ptlTopLock->uTLCount); 01727 } 01728 01729 END_REENTERCRIT(); 01730 01731 return uTLCount; 01732 } 01733 #endif 01734 01735 01736 /***************************************************************************\ 01737 * CreateShadowTL 01738 * 01739 * This function creates a shaddow for the stack allocated ptl parameter 01740 * in the global thread locks arrays 01741 * 01742 * 08-04-99 MCostea Created. 01743 \***************************************************************************/ 01744 01745 #if DBG 01746 void 01747 CreateShadowTL(PTL ptl) 01748 { 01749 PTL pTLNextFree; 01750 if (gFreeTLList->next == NULL) { 01751 UserAssert(gcThreadLocksArraysAllocated < MAX_THREAD_LOCKS_ARRAYS && 01752 "No more room in gpaThreadLocksArrays! The system will bugcheck."); 01753 gFreeTLList->next = gpaThreadLocksArrays[gcThreadLocksArraysAllocated] = 01754 UserAllocPoolZInit(sizeof(TL)*MAX_THREAD_LOCKS, TAG_GLOBALTHREADLOCK); 01755 if (gFreeTLList->next == NULL) { 01756 UserAssert("Can't allocate memory for gpaThreadLocksArrays: the system will bugcheck soon!"); 01757 } 01758 InitGlobalThreadLockArray(gcThreadLocksArraysAllocated); 01759 gcThreadLocksArraysAllocated++; 01760 } 01761 pTLNextFree = gFreeTLList->next; 01762 RtlCopyMemory(gFreeTLList, ptl, sizeof(TL)); 01763 gFreeTLList->ptl = ptl; 01764 ptl->ptl = gFreeTLList; 01765 gFreeTLList = pTLNextFree; 01766 } 01767 #endif // DBG 01768 01769 /***************************************************************************\ 01770 * ThreadLock 01771 * 01772 * This api is used for locking objects across callbacks, so they are still 01773 * there when the callback returns. 01774 * 01775 * 03-04-92 ScottLu Created. 01776 \***************************************************************************/ 01777 01778 #if DBG 01779 void 01780 ThreadLock( 01781 PVOID pobj, 01782 PTL ptl) 01783 01784 { 01785 01786 PTHREADINFO ptiCurrent; 01787 PVOID pfnT; 01788 01789 01790 /* 01791 * This is a handy place, because it is called so often, to see if User is 01792 * eating up too much stack. 01793 */ 01794 UserAssert(((ULONG_PTR)&pfnT - (ULONG_PTR)KeGetCurrentThread()->StackLimit) > KERNEL_STACK_MINIMUM_RESERVE); 01795 01796 /* 01797 * Store the address of the object in the thread lock structure and 01798 * link the structure into the thread lock list. 01799 * 01800 * N.B. The lock structure is always linked into the thread lock list 01801 * regardless of whether the object address is NULL. The reason 01802 * this is done is so the lock address does not need to be passed 01803 * to the unlock function since the first entry in the lock list 01804 * is always the entry to be unlocked. 01805 */ 01806 01807 UserAssert(!(PpiCurrent()->W32PF_Flags & W32PF_TERMINATED)); 01808 ptiCurrent = PtiCurrent(); 01809 UserAssert(ptiCurrent); 01810 01811 /* 01812 * Get the callers address and validate the thread lock list. 01813 */ 01814 RtlGetCallersAddress(&ptl->pfnCaller, &pfnT); 01815 ptl->pW32Thread = (PW32THREAD)ptiCurrent; 01816 01817 ptl->next = ptiCurrent->ptl; 01818 ptiCurrent->ptl = ptl; 01819 ptl->pobj = pobj; 01820 if (pobj != NULL) { 01821 HMLockObject(pobj); 01822 } 01823 CreateShadowTL(ptl); 01824 ValidateThreadLocks(ptl, ptl->next, (ULONG_PTR)&pobj, TRUE); 01825 return; 01826 } 01827 #endif 01828 01829 01830 /***************************************************************************\ 01831 * ThreadLockExchange 01832 * 01833 * Reuses a TL structure by locking the new object and unlocking 01834 * the old one. This is used where you enumerate a list of 01835 * structure locked objects, e.g. the window list. 01836 * 01837 * History: 01838 * 05-Mar-1997 adams Created. 01839 \***************************************************************************/ 01840 01841 #if DBG 01842 PVOID 01843 ThreadLockExchange(PVOID pobj, PTL ptl) 01844 { 01845 PTHREADINFO ptiCurrent; 01846 PVOID pobjOld; 01847 PVOID pfnT; 01848 01849 /* 01850 * This is a handy place, because it is called so often, to see if User is 01851 * eating up too much stack. 01852 */ 01853 UserAssert((ULONG_PTR)&pfnT - (ULONG_PTR)KeGetCurrentThread()->StackLimit > KERNEL_STACK_MINIMUM_RESERVE); 01854 01855 /* 01856 * Store the address of the object in the thread lock structure and 01857 * link the structure into the thread lock list. 01858 * 01859 * N.B. The lock structure is always linked into the thread lock list 01860 * regardless of whether the object address is NULL. The reason 01861 * this is done is so the lock address does not need to be passed 01862 * to the unlock function since the first entry in the lock list 01863 * is always the entry to be unlocked. 01864 */ 01865 01866 UserAssert(!(PpiCurrent()->W32PF_Flags & W32PF_TERMINATED)); 01867 ptiCurrent = PtiCurrent(); 01868 UserAssert(ptiCurrent); 01869 01870 /* 01871 * Get the callers address. 01872 */ 01873 RtlGetCallersAddress(&ptl->pfnCaller, &pfnT); 01874 UserAssert(ptl->pW32Thread == (PW32THREAD)ptiCurrent); 01875 01876 /* 01877 * Remember the old object. 01878 */ 01879 pobjOld = ptl->pobj; 01880 01881 /* 01882 * Store and lock the new object. It is important to do this step 01883 * before unlocking the old object, since the new object might be 01884 * structure locked by the old object. 01885 */ 01886 ptl->pobj = pobj; 01887 if (pobj != NULL) { 01888 HMLockObject(pobj); 01889 } 01890 01891 /* 01892 * Unlock the old object. 01893 */ 01894 if (pobjOld) { 01895 pobjOld = HMUnlockObject((PHEAD)pobjOld); 01896 } 01897 /* 01898 * Validate the entire thread lock list. 01899 */ 01900 ValidateThreadLocks(NULL, ptiCurrent->ptl, (ULONG_PTR)&pobj, TRUE); 01901 { 01902 /* 01903 * Maintain gFreeTLList 01904 */ 01905 UserAssert(ptl->ptl->ptl == ptl); 01906 UserAssert(ptl->ptl->pobj == pobjOld); 01907 ptl->ptl->pobj = pobj; 01908 ptl->ptl->pfnCaller = ptl->pfnCaller; 01909 } 01910 01911 return pobjOld; 01912 } 01913 #endif 01914 01915 01916 /* 01917 * The thread locking routines should be optimized for time, not size, 01918 * since they get called so often. 01919 */ 01920 #pragma optimize("t", on) 01921 01922 /***************************************************************************\ 01923 * ThreadUnlock1 01924 * 01925 * This api unlocks a thread locked object. Returns pobj if the object 01926 * was *not* destroyed (meaning the pointer is still valid). 01927 * 01928 * N.B. In a free build the first entry in the thread lock list is unlocked. 01929 * 01930 * 03-04-92 ScottLu Created. 01931 \***************************************************************************/ 01932 01933 #if DBG 01934 PVOID 01935 ThreadUnlock1( 01936 PTL ptlIn) 01937 #else 01938 PVOID 01939 ThreadUnlock1( 01940 VOID) 01941 #endif 01942 { 01943 PHEAD phead; 01944 PTHREADINFO ptiCurrent; 01945 PTL ptl; 01946 01947 ptiCurrent = PtiCurrent(); 01948 ptl = ptiCurrent->ptl; 01949 UserAssert(ptl != NULL); 01950 /* 01951 * Validate the thread lock list. 01952 */ 01953 ValidateThreadLocks(NULL, ptl, (ULONG_PTR)&ptlIn, TRUE); 01954 /* 01955 * Make sure the caller wants to unlock the top lock. 01956 */ 01957 UserAssert(ptlIn == ptl); 01958 ptiCurrent->ptl = ptl->next; 01959 /* 01960 * If the object address is not NULL, then unlock the object. 01961 */ 01962 phead = (PHEAD)(ptl->pobj); 01963 if (phead != NULL) { 01964 01965 /* 01966 * Unlock the object. 01967 */ 01968 01969 phead = (PHEAD)HMUnlockObject(phead); 01970 } 01971 #if DBG 01972 { 01973 /* 01974 * Remove the corresponding element from gFreeTLList 01975 */ 01976 ptl->ptl->next = gFreeTLList; 01977 ptl->ptl->uTLCount += TL_FREED_PATTERN; 01978 gFreeTLList = ptl->ptl; 01979 } 01980 #endif 01981 return (PVOID)phead; 01982 } 01983 01984 /* 01985 * Switch back to default optimization. 01986 */ 01987 #pragma optimize("", on) 01988 01989 /***************************************************************************\ 01990 * CheckLock 01991 * 01992 * This routine only exists in DBG builds - it checks to make sure objects 01993 * are thread locked. 01994 * 01995 * 03-09-92 ScottLu Created. 01996 \***************************************************************************/ 01997 01998 #if DBG 01999 void CheckLock( 02000 PVOID pobj) 02001 { 02002 PTHREADINFO ptiCurrent = PtiCurrentShared(); 02003 PTL ptl; 02004 02005 if (pobj == NULL) { 02006 return; 02007 } 02008 02009 /* 02010 * Validate all locks first 02011 */ 02012 UserAssert(ptiCurrent != NULL); 02013 ValidateThreadLocks(NULL, ptiCurrent->ptl, (ULONG_PTR)&pobj, TRUE); 02014 02015 for (ptl = ptiCurrent->ptl; ptl != NULL; ptl=ptl->next) { 02016 if (ptl->pobj == pobj) 02017 return; 02018 } 02019 02020 /* 02021 * WM_FINALDESTROY messages get sent without thread locking, so if 02022 * marked for destruction, don't print the message. 02023 */ 02024 if (HMPheFromObject(pobj)->bFlags & HANDLEF_DESTROY) 02025 return; 02026 02027 RIPMSG1(RIP_ERROR, "Object not thread locked! %#p", pobj); 02028 } 02029 #endif 02030 02031 02032 /***************************************************************************\ 02033 * HMDestroyUnlockedObject 02034 * 02035 * Destroy an object based on an unlock or cleanup from thread or 02036 * process termination. 02037 * 02038 * The functions called to destroy a particular object can be called 02039 * directly from code as well as the result of an unlock. Destroy 02040 * functions have the following 4 sections. 02041 * 02042 * (1) Remove the object from a list or other global 02043 * context. If the destroy function has to leave the 02044 * critical section (e.g. make an xxx call), it must 02045 * do so in this step. 02046 * 02047 * (2) Call HMMarkDestroy, and return if HMMarkDestroy 02048 * returns FALSE. This is required. 02049 * 02050 * (3) Destroy resources held by the objects - locks to 02051 * other objects, alloc'd memory, etc. This is required. 02052 * 02053 * (4) Free the memory of the object and its handle by calling 02054 * HMFreeObject. This is required. 02055 * 02056 * Note that if the object is locked when it's destroy function 02057 * is called directly, step (1) will be repeated when the object is 02058 * unlocked. We should probably check for this in the destroy functions, 02059 * which we currently do not do. 02060 * 02061 * Note that we could be destroying this object in a context different 02062 * than the one that created it. This is very important to understand 02063 * since in lots of code the "current thread" is referenced and assumed 02064 * as the creator. 02065 * 02066 * 02-10-92 ScottLu Created. 02067 \***************************************************************************/ 02068 02069 void HMDestroyUnlockedObject( 02070 PHE phe) 02071 { 02072 BEGINATOMICCHECK(); 02073 02074 /* 02075 * Remember that we're destroying this object so we don't try to destroy 02076 * it again when the lock count goes from != 0 to 0 (especially true 02077 * for thread locks). 02078 */ 02079 phe->bFlags |= HANDLEF_INDESTROY; 02080 02081 /* 02082 * This'll call the destroy handler for this object type. 02083 */ 02084 (*gahti[phe->bType].fnDestroy)(phe->phead); 02085 02086 /* 02087 * HANDLEF_INDESTROY is supposed to be cleared either by HMMarkObjectDestroy 02088 * or by HMFreeObject; the destroy handler was supposed to call at least 02089 * the former. 02090 */ 02091 UserAssert(!(phe->bFlags & HANDLEF_INDESTROY)); 02092 02093 /* 02094 * If the object wasn't freed, it must be marked as destroyed 02095 * and must have a lock count 02096 */ 02097 UserAssert((phe->bType == TYPE_FREE) 02098 || ((phe->bFlags & HANDLEF_DESTROY) && (phe->phead->cLockObj > 0))); 02099 02100 ENDATOMICCHECK(); 02101 } 02102 02103 02104 /***************************************************************************\ 02105 * HMChangeOwnerThread 02106 * 02107 * Changes the owning thread of an object. 02108 * 02109 * 09-13-93 JimA Created. 02110 \***************************************************************************/ 02111 02112 VOID HMChangeOwnerThread( 02113 PVOID pobj, 02114 PTHREADINFO pti) 02115 { 02116 PHE phe = HMPheFromObject(pobj); 02117 PTHREADINFO ptiOld = ((PTHROBJHEAD)(pobj))->pti; 02118 PWND pwnd; 02119 PPCLS ppcls; 02120 PPROCESSINFO ppi; 02121 02122 UserAssert(HMObjectFlags(pobj) & OCF_THREADOWNED); 02123 UserAssert(pti != NULL); 02124 02125 ((PTHREADINFO)phe->pOwner)->ppi->UserHandleCount--; 02126 02127 ((PTHROBJHEAD)pobj)->pti = phe->pOwner = pti; 02128 02129 ((PTHREADINFO)phe->pOwner)->ppi->UserHandleCount++; 02130 02131 DBGValidateHandleQuota(); 02132 02133 /* 02134 * If this is a window, update the window counts. 02135 */ 02136 switch (phe->bType) { 02137 case TYPE_WINDOW: 02138 /* 02139 * Desktop thread used to hit this assert in HYDRA 02140 * because pti == ptiOld 02141 */ 02142 UserAssert(ptiOld->cWindows > 0 || ptiOld == pti); 02143 pti->cWindows++; 02144 ptiOld->cWindows--; 02145 02146 pwnd = (PWND)pobj; 02147 02148 /* 02149 * Make sure thread visible window count is properly updated. 02150 */ 02151 if (TestWF(pwnd, WFVISIBLE) && FVisCountable(pwnd)) { 02152 pti->cVisWindows++; 02153 ptiOld->cVisWindows--; 02154 } 02155 02156 /* 02157 * If the owning process is changing, fix up 02158 * the window class. 02159 */ 02160 if (pti->ppi != ptiOld->ppi) { 02161 02162 ppcls = GetClassPtr(pwnd->pcls->atomClassName, pti->ppi, hModuleWin); 02163 02164 if (ppcls == NULL) { 02165 if (pwnd->head.rpdesk) 02166 ppi = pwnd->head.rpdesk->rpwinstaParent->pTerm->ptiDesktop->ppi; 02167 else 02168 ppi = PpiCurrent(); 02169 ppcls = GetClassPtr(gpsi->atomSysClass[ICLS_ICONTITLE], ppi, hModuleWin); 02170 } 02171 UserAssert(ppcls); 02172 02173 /* 02174 * The window is either destroyed or the desktop of the class is 02175 * the same as the window's desktop 02176 */ 02177 UserAssert((*ppcls)->rpdeskParent == pwnd->head.rpdesk || 02178 TestWF(pwnd, WFDESTROYED)); 02179 02180 DereferenceClass(pwnd); 02181 pwnd->pcls = *ppcls; 02182 pwnd->pcls->cWndReferenceCount++; 02183 } 02184 break; 02185 02186 case TYPE_HOOK: 02187 /* 02188 * If this is a global hook, remember this hook's desktop so we'll be 02189 * able to unlink it later (gptiRit might switch to a different desktop 02190 * at any time). 02191 */ 02192 UserAssert(!!(((PHOOK)pobj)->flags & HF_GLOBAL) ^ (((PHOOK)pobj)->ptiHooked != NULL)); 02193 if (((PHOOK)pobj)->flags & HF_GLOBAL) { 02194 UserAssert(pti == gptiRit); 02195 LockDesktop(&((PHOOK)pobj)->rpdesk, ptiOld->rpdesk, LDL_HOOK_DESK, 0); 02196 } else { 02197 /* 02198 * This must be a hook on another thread or it was supposed to be 02199 * gone by now. 02200 */ 02201 UserAssert(((PHOOK)pobj)->ptiHooked != ptiOld); 02202 } 02203 break; 02204 02205 default: 02206 break; 02207 } 02208 } 02209 02210 /***************************************************************************\ 02211 * HMChangeOwnerProcess 02212 * 02213 * Changes the owning process of an object. 02214 * 02215 * 04-15-97 JerrySh Created. 02216 * 09-23-97 GerardoB Changed parameters (and name) so HMDestroyUnlockedObject 02217 * could use this function (instead of duplicating the code there) 02218 \***************************************************************************/ 02219 02220 VOID HMChangeOwnerPheProcess( 02221 PHE phe, 02222 PTHREADINFO pti) 02223 { 02224 PPROCESSINFO ppiOwner = (PPROCESSINFO)(phe->pOwner); 02225 PVOID pobj = phe->phead; 02226 02227 UserAssert(HMObjectFlags(pobj) & OCF_PROCESSOWNED); 02228 UserAssert(pti != NULL); 02229 /* 02230 * Dec current owner handle count 02231 */ 02232 ppiOwner->UserHandleCount--; 02233 /* 02234 * hTaskWow 02235 */ 02236 if ((pti->TIF_flags & TIF_16BIT) && (pti->ptdb)) { 02237 ((PPROCOBJHEAD)pobj)->hTaskWow = pti->ptdb->hTaskWow; 02238 } else { 02239 ((PPROCOBJHEAD)pobj)->hTaskWow = 0; 02240 } 02241 /* 02242 * ppi 02243 */ 02244 if (gahti[phe->bType].bObjectCreateFlags & OCF_MARKPROCESS) { 02245 ((PPROCMARKHEAD)pobj)->ppi = pti->ppi; 02246 } 02247 /* 02248 * Set new owner in handle entry 02249 */ 02250 phe->pOwner = pti->ppi; 02251 /* 02252 * Inc new owner handle count 02253 */ 02254 ((PPROCESSINFO)(phe->pOwner))->UserHandleCount++; 02255 /* 02256 * If the handle is a cursor, adjust GDI cursor handle count 02257 */ 02258 if (phe->bType == TYPE_CURSOR) { 02259 GreDecQuotaCount((PW32PROCESS)ppiOwner); 02260 GreIncQuotaCount((PW32PROCESS)phe->pOwner); 02261 02262 if (((PCURSOR)pobj)->hbmColor) { 02263 GreDecQuotaCount((PW32PROCESS)ppiOwner); 02264 GreIncQuotaCount((PW32PROCESS)phe->pOwner); 02265 } 02266 } 02267 02268 DBGValidateHandleQuota(); 02269 } 02270 02271 /***************************************************************************\ 02272 * DestroyThreadsObjects 02273 * 02274 * Goes through the handle table list and destroy all objects owned by this 02275 * thread, because the thread is going away (either nicely, it faulted, or 02276 * was terminated). It is ok to destroy the objects in any order, because 02277 * object locking will ensure that they get destroyed in the right order. 02278 * 02279 * This routine gets called in the context of the thread that is exiting. 02280 * 02281 * 02-08-92 ScottLu Created. 02282 \***************************************************************************/ 02283 02284 VOID DestroyThreadsObjects() 02285 { 02286 PTHREADINFO ptiCurrent; 02287 HANDLEENTRY volatile * (*pphe); 02288 PHE pheT; 02289 DWORD i; 02290 02291 ptiCurrent = PtiCurrent(); 02292 DBGValidateHandleQuota(); 02293 02294 /* 02295 * Before any window destruction occurs, we need to destroy any dcs 02296 * in use in the dc cache. When a dc is checked out, it is marked owned, 02297 * which makes gdi's process cleanup code delete it when a process 02298 * goes away. We need to similarly destroy the cache entry of any dcs 02299 * in use by the exiting process. 02300 */ 02301 DestroyCacheDCEntries(ptiCurrent); 02302 02303 /* 02304 * Remove any thread locks that may exist for this thread. 02305 */ 02306 while (ptiCurrent->ptl != NULL) { 02307 02308 UserAssert((ULONG_PTR)ptiCurrent->ptl > (ULONG_PTR)&i); 02309 UserAssert((ULONG_PTR)ptiCurrent->ptl < (ULONG_PTR)KeGetCurrentThread()->StackBase); 02310 ThreadUnlock(ptiCurrent->ptl); 02311 } 02312 02313 /* 02314 * CleanupPool stuff must happen before handle table clean up (as it always has been). 02315 * This is because SMWPs can be HM objects and still be locked in ptlPool. 02316 * If the handle is destroyed first (and it's not locked) we would end up with a 02317 * bogus pointer in ptlPool. If ptlPool is cleaned up first, the handle will be freed 02318 * or properly preserved if locked. 02319 */ 02320 CleanupW32ThreadLocks((PW32THREAD)ptiCurrent); 02321 02322 /* 02323 * Eventhough HMDestroyUnlockedObject might call xxxDestroyWindow, the 02324 * following loop is not supposed to leave the critical section. We must 02325 * have called PatchThreadWindows before coming here. 02326 */ 02327 BEGINATOMICCHECK(); 02328 02329 /* 02330 * Loop through the table destroying all objects created by the current 02331 * thread. All objects will get destroyed in their proper order simply 02332 * because of the object locking. 02333 */ 02334 pphe = &gSharedInfo.aheList; 02335 for (i = 0; i <= giheLast; i++) { 02336 /* 02337 * This pointer is done this way because it can change when we leave 02338 * the critical section below. The above volatile ensures that we 02339 * always use the most current value 02340 */ 02341 pheT = (PHE)((*pphe) + i); 02342 02343 /* 02344 * Check against free before we look at pti... because pq is stored 02345 * in the object itself, which won't be there if TYPE_FREE. 02346 */ 02347 if (pheT->bType == TYPE_FREE) 02348 continue; 02349 02350 /* 02351 * If a menu refererences a window owned by this thread, unlock 02352 * the window. This is done to prevent calling xxxDestroyWindow 02353 * during process cleanup. 02354 */ 02355 if (gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) { 02356 if (pheT->bType == TYPE_MENU) { 02357 PWND pwnd = ((PMENU)pheT->phead)->spwndNotify; 02358 02359 if (pwnd != NULL && GETPTI(pwnd) == ptiCurrent) 02360 Unlock(&((PMENU)pheT->phead)->spwndNotify); 02361 } 02362 continue; 02363 } 02364 02365 /* 02366 * Destroy those objects created by this queue. 02367 */ 02368 if ((PTHREADINFO)pheT->pOwner != ptiCurrent) 02369 continue; 02370 02371 UserAssert(gahti[pheT->bType].bObjectCreateFlags & OCF_THREADOWNED); 02372 02373 /* 02374 * Make sure this object isn't already marked to be destroyed - we'll 02375 * do no good if we try to destroy it now since it is locked. 02376 */ 02377 if (pheT->bFlags & HANDLEF_DESTROY) { 02378 continue; 02379 } 02380 02381 /* 02382 * Destroy this object. 02383 */ 02384 HMDestroyUnlockedObject(pheT); 02385 } 02386 02387 ENDATOMICCHECK(); 02388 DBGValidateHandleQuota(); 02389 } 02390 02391 #if DBG 02392 VOID ShowLocks( 02393 PHE phe) 02394 { 02395 PLR plr = phe->plr; 02396 INT c; 02397 02398 RIPMSG2(RIP_WARNING | RIP_THERESMORE, 02399 "Lock records for %s %#p:", 02400 gahti[phe->bType].szObjectType, phe->phead->h); 02401 /* 02402 * We have the handle entry: 'head' and 'he' are both filled in. Dump 02403 * the lock records. Remember the first record is the last transaction!! 02404 */ 02405 c = 0; 02406 while (plr != NULL) { 02407 char achPrint[80]; 02408 02409 if (plr->ppobj == LOCKRECORD_MARKDESTROY) { 02410 strcpy(achPrint, "Destroyed with"); 02411 } else if ((int)plr->cLockObj <= 0) { 02412 strcpy(achPrint, " Unlock"); 02413 } else { 02414 /* 02415 * Find corresponding unlock; 02416 */ 02417 { 02418 PLR plrUnlock; 02419 DWORD cT; 02420 DWORD cUnlock; 02421 02422 plrUnlock = phe->plr; 02423 cT = 0; 02424 cUnlock = (DWORD)-1; 02425 02426 while (plrUnlock != plr) { 02427 if (plrUnlock->ppobj == plr->ppobj) { 02428 if ((int)plrUnlock->cLockObj <= 0) { 02429 // a matching unlock found 02430 cUnlock = cT; 02431 } else { 02432 // the unlock #cUnlock matches this lock #cT, thus 02433 // #cUnlock is not the unlock we were looking for. 02434 cUnlock = (DWORD)-1; 02435 } 02436 } 02437 plrUnlock = plrUnlock->plrNext; 02438 cT++; 02439 } 02440 if (cUnlock == (DWORD)-1) { 02441 /* 02442 * Corresponding unlock not found! 02443 * This may not mean something is wrong: the structure 02444 * containing the pointer to the object may have moved 02445 * during a reallocation. This can cause ppobj at Unlock 02446 * time to differ from that recorded at Lock time. 02447 * (Warning: moving structures like this may cause a Lock 02448 * and an Unlock to be misidentified as a pair, if by a 02449 * stroke of incredibly bad luck, the new location of a 02450 * pointer to an object is now where an old pointer to the 02451 * same object used to be) 02452 */ 02453 sprintf(achPrint, "Unmatched Lock"); 02454 } else { 02455 sprintf(achPrint, "lock #%ld", cUnlock); 02456 } 02457 } 02458 } 02459 02460 RIPMSG4(RIP_WARNING | RIP_NONAME | RIP_THERESMORE, 02461 " %s cLock=%d, pobj at %#p, code at %#p", 02462 achPrint, 02463 abs((int)plr->cLockObj), 02464 plr->ppobj, 02465 plr->trace[0]); 02466 02467 plr = plr->plrNext; 02468 c++; 02469 } 02470 02471 RIPMSG1(RIP_WARNING | RIP_NONAME, " 0x%lx records", c); 02472 } 02473 #endif 02474 02475 void FixupCursor( 02476 PCURSOR pcur, 02477 PPROCESSINFO ppi) 02478 { 02479 int i; 02480 PACON pacon = (PACON)pcur; 02481 02482 if (pcur->head.ppi == NULL) { 02483 pcur->head.ppi = ppi; 02484 } 02485 02486 if (pacon->CURSORF_flags & CURSORF_ACON) { 02487 for (i = 0; i < pacon->cpcur; i++) { 02488 02489 UserAssert(pacon->aspcur[i]->CURSORF_flags & CURSORF_ACONFRAME); 02490 02491 if (pacon->aspcur[i]->head.ppi == NULL) { 02492 pacon->aspcur[i]->head.ppi = ppi; 02493 } 02494 } 02495 } 02496 } 02497 02498 /***************************************************************************\ 02499 * DestroyProcessesObjects 02500 * 02501 * Goes through the handle table list and destroy all objects owned by this 02502 * process, because the process is going away (either nicely, it faulted, or 02503 * was terminated). It is ok to destroy the objects in any order, because 02504 * object locking will ensure that they get destroyed in the right order. 02505 * 02506 * This routine gets called in the context of the last thread in the process. 02507 * 02508 * 08-17-92 JimA Created. 02509 \***************************************************************************/ 02510 02511 VOID DestroyProcessesObjects( 02512 PPROCESSINFO ppi) 02513 { 02514 PHE pheT, pheMax; 02515 BOOL bGlobal = (ISTS() && ppi->Process == gpepCSRSS); 02516 02517 /* 02518 * Loop through the table destroying all objects created by the current 02519 * process. All objects will get destroyed in their proper order simply 02520 * because of the object locking. 02521 */ 02522 DBGValidateHandleQuota(); 02523 pheMax = &gSharedInfo.aheList[giheLast]; 02524 02525 for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) { 02526 02527 /* 02528 * Check against free before we look at ppi... because pq is stored 02529 * in the object itself, which won't be there if TYPE_FREE. 02530 */ 02531 if (pheT->bType == TYPE_FREE) 02532 continue; 02533 02534 /* 02535 * Destroy those objects created by this queue. 02536 */ 02537 if (!(gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) || 02538 (PPROCESSINFO)pheT->pOwner != ppi) 02539 continue; 02540 02541 /* 02542 * Make sure this object isn't already marked to be destroyed - we'll 02543 * do no good if we try to destroy it now since it is locked. 02544 * Change the owner since the process is going away 02545 */ 02546 if (pheT->bFlags & HANDLEF_DESTROY) { 02547 HMChangeOwnerPheProcess(pheT, gptiRit); 02548 continue; 02549 } 02550 02551 if (bGlobal) { 02552 02553 /* 02554 * For global cursors set the ppi in the pcur 02555 * to be CSRSS 02556 */ 02557 if (pheT->bType == TYPE_CURSOR) { 02558 FixupCursor((PCURSOR)pheT->phead, ppi); 02559 } 02560 } 02561 02562 /* 02563 * Destroy this object. 02564 */ 02565 HMDestroyUnlockedObject(pheT); 02566 02567 /* 02568 * When the object is freed, the handle type is set to TYPE_FREE. 02569 * Zombie this object, since its process is going away and it couldn't 02570 * be freed. This may include unlinking it and resetting the owner. 02571 */ 02572 if (pheT->bType != TYPE_FREE) { 02573 if (pheT->bType == TYPE_CURSOR) { 02574 RIPMSG1(RIP_WARNING, "About to zombie pcur %#p\n", 02575 pheT->phead); 02576 02577 ZombieCursor((PCURSOR)pheT->phead); 02578 } else { 02579 HMChangeOwnerPheProcess(pheT, gptiRit); 02580 } 02581 } 02582 } /* for loop */ 02583 DBGValidateHandleQuota(); 02584 } 02585 02586 /***************************************************************************\ 02587 * MarkThreadsObjects 02588 * 02589 * This is called for the *final* exiting condition when a thread 02590 * may have objects still around... in which case their owner must 02591 * be changed to something "safe" that won't be going away. 02592 * 02593 * 03-02-92 ScottLu Created. 02594 \***************************************************************************/ 02595 void MarkThreadsObjects( 02596 PTHREADINFO pti) 02597 { 02598 PHE pheT, pheMax; 02599 02600 pheMax = &gSharedInfo.aheList[giheLast]; 02601 for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) { 02602 /* 02603 * Check against free before we look at pti... because pti is stored 02604 * in the object itself, which won't be there if TYPE_FREE. 02605 */ 02606 if (pheT->bType == TYPE_FREE) 02607 continue; 02608 02609 /* 02610 * Change ownership! 02611 */ 02612 if (gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED || 02613 (PTHREADINFO)pheT->pOwner != pti) 02614 continue; 02615 02616 #if DBG 02617 /* 02618 * This is just to make sure that RIT or DT never get here 02619 */ 02620 if (ISTS() && (pti == gptiRit || pti == gTermIO.ptiDesktop)) { 02621 RIPMSG2(RIP_ERROR, "pti %#p is RIT or DT. phe %#p\n", pti, pheT); 02622 } 02623 #endif 02624 02625 HMChangeOwnerThread(pheT->phead, gptiRit); 02626 02627 #if DEBUGTAGS 02628 02629 if (IsDbgTagEnabled(DBGTAG_TrackLocks)) { 02630 /* 02631 * Object still around: print warning message. 02632 */ 02633 if (pheT->bFlags & HANDLEF_DESTROY) { 02634 TAGMSG2(DBGTAG_TrackLocks, 02635 "Zombie %s %#p still locked", 02636 gahti[pheT->bType].szObjectType, pheT->phead->h); 02637 } else { 02638 TAGMSG1(DBGTAG_TrackLocks, 02639 "Thread object %#p not destroyed.\n", 02640 pheT->phead->h); 02641 } 02642 02643 ShowLocks(pheT); 02644 } 02645 02646 #endif // DEBUGTAGS 02647 } 02648 } 02649 02650 /***************************************************************************\ 02651 * HMRelocateLockRecord 02652 * 02653 * If a pointer to a locked object has been relocated, then this routine will 02654 * adjust the lock record accordingly. Must be called after the relocation. 02655 * 02656 * The arguments are: 02657 * ppobjNew - the address of the new pointer 02658 * MUST already contain the pointer to the object!! 02659 * cbDelta - the amount by which this pointer was moved. 02660 * 02661 * Using this routine appropriately will prevent spurious "unmatched lock" 02662 * reports. See mnchange.c for an example. 02663 * 02664 * 02665 * 03-18-93 IanJa Created. 02666 \***************************************************************************/ 02667 02668 #if DBG 02669 02670 BOOL HMRelocateLockRecord( 02671 PVOID ppobjNew, 02672 LONG_PTR cbDelta) 02673 { 02674 PHE phe; 02675 PVOID ppobjOld = (PBYTE)ppobjNew - cbDelta; 02676 PHEAD pobj; 02677 PLR plr; 02678 02679 if (ppobjNew == NULL) { 02680 return FALSE; 02681 } 02682 02683 pobj = *(PHEAD *)ppobjNew; 02684 02685 if (pobj == NULL) { 02686 return FALSE; 02687 } 02688 02689 phe = HMPheFromObject(pobj); 02690 if (phe->phead != pobj) { 02691 RIPMSG3(RIP_WARNING, 02692 "HmRelocateLockRecord(%#p, %lx) - %#p is bad pobj\n", 02693 ppobjNew, cbDelta, pobj); 02694 02695 return FALSE; 02696 } 02697 02698 plr = phe->plr; 02699 02700 while (plr != NULL) { 02701 if (plr->ppobj == ppobjOld) { 02702 (PBYTE)(plr->ppobj) += cbDelta; 02703 return TRUE; 02704 } 02705 plr = plr->plrNext; 02706 } 02707 02708 RIPMSG2(RIP_WARNING, 02709 "HmRelocateLockRecord(%#p, %lx) - couldn't find lock record\n", 02710 ppobjNew, cbDelta); 02711 02712 ShowLocks(phe); 02713 return FALSE; 02714 } 02715 02716 02717 BOOL HMUnrecordLock( 02718 PVOID ppobj, 02719 PVOID pobj) 02720 { 02721 PHE phe; 02722 PLR plr; 02723 PLR *pplr; 02724 02725 phe = HMPheFromObject(pobj); 02726 02727 pplr = &(phe->plr); 02728 plr = *pplr; 02729 02730 /* 02731 * Find corresponding lock; 02732 */ 02733 while (plr != NULL) { 02734 if (plr->ppobj == ppobj) { 02735 /* 02736 * Remove the lock from the list... 02737 */ 02738 *pplr = plr->plrNext; // unlink it 02739 plr->plrNext = NULL; // make the dead entry safe (?) 02740 02741 /* 02742 * ...and free it. 02743 */ 02744 FreeLockRecord(plr); 02745 return TRUE; 02746 } 02747 pplr = &(plr->plrNext); 02748 plr = *pplr; 02749 } 02750 02751 RIPMSG2(RIP_WARNING, "Could not find lock for ppobj %#p pobj %#p", 02752 ppobj, pobj); 02753 02754 return FALSE; 02755 } 02756 02757 #endif // DBG 02758 02759 /***************************************************************************\ 02760 * _QueryUserHandles 02761 * 02762 * This function retrieves the USER handle counters for all processes 02763 * specified by their client ID in the paPids array 02764 * Specify QUC_PID_TOTAL to retrieve totals for all processes in the system 02765 * 02766 * Parameters: 02767 * paPids - pointer to an array of pids (DWORDS) that we're interested in 02768 * dwNumInstances - number of DWORDS in paPids 02769 * pdwResult - will receive TYPES_CTYPESxdwNumInstances counters 02770 * 02771 * returns: none 02772 * 02773 * 07-25-97 mcostea Created 02774 \***************************************************************************/ 02775 02776 VOID _QueryUserHandles( 02777 LPDWORD paPids, 02778 DWORD dwNumInstances, 02779 DWORD dwResult[][TYPE_CTYPES]) 02780 { 02781 PHE pheCurPos; // Current position in the table 02782 PHE pheMax; // address of last table entry 02783 DWORD index; 02784 DWORD pid; 02785 DWORD dwTotalCounters[TYPE_CTYPES]; // system wide counters 02786 02787 RtlZeroMemory(dwTotalCounters, TYPE_CTYPES*sizeof(DWORD)); 02788 RtlZeroMemory(dwResult, dwNumInstances*TYPE_CTYPES*sizeof(DWORD)); 02789 /* 02790 * Walk the handle table and update the counters 02791 */ 02792 pheMax = &gSharedInfo.aheList[giheLast]; 02793 for(pheCurPos = gSharedInfo.aheList; pheCurPos <= pheMax; pheCurPos++) { 02794 02795 UserAssert(pheCurPos->bType < TYPE_CTYPES); 02796 02797 pid = 0; 02798 02799 if (pheCurPos->pOwner) { 02800 02801 if (gahti[pheCurPos->bType].bObjectCreateFlags & OCF_PROCESSOWNED) { 02802 /* 02803 * Object is owned by process 02804 * some objects may not have an owner 02805 */ 02806 pid = HandleToUlong(((PPROCESSINFO)pheCurPos->pOwner)->Process->UniqueProcessId); 02807 } 02808 else if (gahti[pheCurPos->bType].bObjectCreateFlags & OCF_THREADOWNED) { 02809 /* 02810 * Object owned by thread 02811 */ 02812 pid = HandleToUlong(((PTHREADINFO)pheCurPos->pOwner)->pEThread->ThreadsProcess->UniqueProcessId); 02813 } 02814 } 02815 /* 02816 * search to see if we are interested in this process 02817 * unowned handles are reported for the "System" process whose pid is 0 02818 */ 02819 for (index = 0; index < dwNumInstances; index++) { 02820 02821 if (paPids[index] == pid) { 02822 dwResult[index][pheCurPos->bType]++; 02823 } 02824 } 02825 /* 02826 * update the totals 02827 */ 02828 dwTotalCounters[pheCurPos->bType]++; 02829 } 02830 02831 /* 02832 * search to see if we are interested in the totals 02833 */ 02834 for (index = 0; index < dwNumInstances; index++) { 02835 02836 if (paPids[index] == QUC_PID_TOTAL) { 02837 02838 RtlMoveMemory(dwResult[index], dwTotalCounters, sizeof(dwTotalCounters)); 02839 } 02840 } 02841 02842 } 02843 02844 /***************************************************************************\ 02845 * HMCleanupGrantedHandle 02846 * 02847 * This function is called to cleanup this handle from pW32Job->pgh arrays. 02848 * It walks the job list to find jobs that have the handle granted. 02849 * 02850 * HISTORY: 02851 * 22 Jul 97 CLupu Created 02852 \***************************************************************************/ 02853 void HMCleanupGrantedHandle( 02854 HANDLE h) 02855 { 02856 PW32JOB pW32Job; 02857 02858 pW32Job = gpJobsList; 02859 02860 while (pW32Job != NULL) { 02861 PULONG_PTR pgh; 02862 DWORD dw; 02863 02864 pgh = pW32Job->pgh; 02865 02866 /* 02867 * search for the handle in the array. 02868 */ 02869 for (dw = 0; dw < pW32Job->ughCrt; dw++) { 02870 if (*(pgh + dw) == (ULONG_PTR)h) { 02871 02872 /* 02873 * found the handle granted to this process 02874 */ 02875 RtlMoveMemory(pgh + dw, 02876 pgh + dw + 1, 02877 (pW32Job->ughCrt - dw - 1) * sizeof(*pgh)); 02878 02879 (pW32Job->ughCrt)--; 02880 02881 /* 02882 * we should shrink the array also 02883 */ 02884 02885 break; 02886 } 02887 } 02888 02889 pW32Job = pW32Job->pNext; 02890 } 02891 }

Generated on Sat May 15 19:40:14 2004 for test by doxygen 1.3.7